1 /*
2 * This file is part of NumptyPhysics
3 * Copyright (C) 2008 Tim Edmonds
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 3 of the
8 * License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 */
16
17 #include <string>
18 #include "Common.h"
19 #include "Config.h"
20 #include "Canvas.h"
21 #include "Path.h"
22
23 #include <SDL/SDL.h>
24 #include <SDL/SDL_image.h>
25
26 #define Window X11Window //oops
27 #include <SDL/SDL_syswm.h>
28 #ifndef WIN32
29 #include <X11/X.h>
30 #include <X11/Xlib.h>
31 #endif
32 #undef Window
33
34 // zoomer.cpp
35 extern SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy);
36
37
38 // extract RGB colour components as 8bit values from RGB888
39 #define R32(p) (((p)>>16)&0xff)
40 #define G32(p) (((p)>>8)&0xff)
41 #define B32(p) ((p)&0xff)
42
43 // extract RGB colour components as 8bit values from RGB565
44 #define R16(p) (((p)>>8)&0xf8)
45 #define G16(p) (((p)>>3)&0xfc)
46 #define B16(p) (((p)<<3)&0xf8)
47
48 #define R16G16B16_TO_RGB888(r,g,b) \
49 ((((r)<<8)&0xff0000) | ((g)&0x00ff00) | (((b)>>8)))
50
51 #define R16G16B16_TO_RGB565(r,g,b) \
52 ((Uint16)( (((r)&0xf800) | (((g)>>5)&0x07e0) | (((b)>>11))&0x001f) ))
53
54 #define RGB888_TO_RGB565(p) \
55 ((Uint16)( (((p)>>8)&0xf800) | (((p)>>5)&0x07e0) | (((p)>>3)&0x001f) ))
56
57
ExtractRgb(uint32 c,int & r,int & g,int & b)58 void ExtractRgb( uint32 c, int& r, int &g, int &b )
59 {
60 r = R32(c); g = G32(c); b = B32(c);
61 }
62
ExtractRgb(uint16 c,int & r,int & g,int & b)63 void ExtractRgb( uint16 c, int& r, int &g, int &b )
64 {
65 r = R16(c); g = G16(c); b = B16(c);
66 }
67
68
69 template <typename PIX>
AlphaBlend(PIX & p,int cr,int cg,int cb,int a,int ia)70 inline void AlphaBlend( PIX& p, int cr, int cg, int cb, int a, int ia )
71 {
72 throw "not implemented";
73 }
74
AlphaBlend(Uint16 & p,int cr,int cg,int cb,int a,int ia)75 inline void AlphaBlend( Uint16& p, int cr, int cg, int cb, int a, int ia )
76 { //565
77 p = R16G16B16_TO_RGB565( a * cr + ia * R16(p),
78 a * cg + ia * G16(p),
79 a * cb + ia * B16(p) );
80 }
81
AlphaBlend(Uint32 & p,int cr,int cg,int cb,int a,int ia)82 inline void AlphaBlend( Uint32& p, int cr, int cg, int cb, int a, int ia )
83
84 { //888
85 p = R16G16B16_TO_RGB888( a * cr + ia * R32(p),
86 a * cg + ia * G32(p),
87 a * cb + ia * B32(p) );
88 }
89
90 #define ALPHA_MAX 0xff
91
92 template <typename PIX, unsigned W>
93 struct AlphaBrush
94 {
95 int m_r, m_g, m_b, m_c;
AlphaBrushAlphaBrush96 inline AlphaBrush( PIX c )
97 {
98 m_c = c;
99 ExtractRgb( c, m_r, m_g, m_b );
100 }
inkAlphaBrush101 inline void ink( PIX* pix, int step, int a )
102 {
103 int ia = ALPHA_MAX - a;
104 int o=-W/2+1;
105 AlphaBlend( *(pix+o*step), m_r, m_g, m_b, a, ia );
106 for ( ; o<=W/2; o++ ) {
107 *(pix+o*step) = m_c;
108 }
109 AlphaBlend( *(pix+o*step), m_r, m_g, m_b, ia, a );
110 }
111 };
112
113 template <typename PIX>
114 struct AlphaBrush<PIX,1>
115 {
116 int m_r, m_g, m_b, m_c;
AlphaBrushAlphaBrush117 inline AlphaBrush( PIX c )
118 {
119 m_c = c;
120 ExtractRgb( c, m_r, m_g, m_b );
121 }
inkAlphaBrush122 inline void ink( PIX* pix, int step, int a )
123 {
124 int ia = ALPHA_MAX - a;
125 AlphaBlend( *(pix-step), m_r, m_g, m_b, a, ia );
126 AlphaBlend( *(pix), m_r, m_g, m_b, ia, a );
127 }
128 };
129
130 template <typename PIX>
131 struct AlphaBrush<PIX,3>
132 {
133 int m_r, m_g, m_b, m_c;
AlphaBrushAlphaBrush134 inline AlphaBrush( PIX c )
135 {
136 m_c = c;
137 ExtractRgb( c, m_r, m_g, m_b );
138 }
inkAlphaBrush139 inline void ink( PIX* pix, int step, int a )
140 {
141 int ia = ALPHA_MAX - a;
142 AlphaBlend( *(pix-step), m_r, m_g, m_b, a, ia );
143 *(pix) = m_c;
144 AlphaBlend( *(pix+step), m_r, m_g, m_b, ia, a );
145 }
146 };
147
148
149
150 template <typename PIX, unsigned THICK>
renderLine(void * buf,int byteStride,int x1,int y1,int x2,int y2,PIX color)151 inline void renderLine( void *buf,
152 int byteStride,
153 int x1, int y1, int x2, int y2,
154 PIX color )
155 {
156 PIX *pix = (PIX*)((char*)buf+byteStride*y1) + x1;
157 int lg_delta, sh_delta, cycle, lg_step, sh_step;
158 int alpha, alpha_step, alpha_reset;
159 int pixStride = byteStride/sizeof(PIX);
160 AlphaBrush<PIX,THICK> brush( color );
161
162 lg_delta = x2 - x1;
163 sh_delta = y2 - y1;
164 lg_step = Sgn(lg_delta);
165 lg_delta = Abs(lg_delta);
166 sh_step = Sgn(sh_delta);
167 sh_delta = Abs(sh_delta);
168 if ( sh_step < 0 ) pixStride = -pixStride;
169
170 // in theory should be able to do this with just a single step
171 // variable - ie: combine cycle and alpha as in wu algorithm
172 if (sh_delta < lg_delta) {
173 cycle = lg_delta >> 1;
174 alpha = ALPHA_MAX >> 1;
175 alpha_step = -(ALPHA_MAX * sh_delta/(lg_delta+1));
176 alpha_reset = alpha_step < 0 ? ALPHA_MAX : 0;
177 int count = lg_step>0 ? x2-x1 : x1-x2;
178 while ( count-- ) {
179 brush.ink( pix, pixStride, alpha );
180 cycle += sh_delta;
181 alpha += alpha_step;
182 pix += lg_step;
183 if (cycle > lg_delta) {
184 cycle -= lg_delta;
185 alpha = alpha_reset;
186 pix += pixStride;
187 }
188 }
189 } else {
190 cycle = sh_delta >> 1;
191 alpha = ALPHA_MAX >> 1;
192 alpha_step = -lg_step * Abs(ALPHA_MAX * lg_delta/(sh_delta+1));
193 alpha_reset = alpha_step < 0 ? ALPHA_MAX : 0;
194 int count = sh_step>0 ? y2-y1 : y1-y2;
195 while ( count-- ) {
196 brush.ink( pix, 1, alpha );
197 cycle += lg_delta;
198 alpha += alpha_step;
199 pix += pixStride;
200 if (cycle > sh_delta) {
201 cycle -= sh_delta;
202 alpha = alpha_reset;
203 pix += lg_step;
204 }
205 }
206 }
207 }
208
209
210 #define SURFACE(cANVASpTR) ((SDL_Surface*)((cANVASpTR)->m_state))
211
Canvas(int w,int h)212 Canvas::Canvas( int w, int h )
213 : m_state(NULL),
214 m_bgColour(0),
215 m_bgImage(NULL)
216 {
217 switch (SDL_GetVideoInfo()->vfmt->BitsPerPixel) {
218 case 16:
219 case 32:
220 m_state = SDL_CreateRGBSurface( SDL_SWSURFACE, w, h,
221 SDL_GetVideoInfo()->vfmt->BitsPerPixel,
222 SDL_GetVideoInfo()->vfmt->Rmask,
223 SDL_GetVideoInfo()->vfmt->Gmask,
224 SDL_GetVideoInfo()->vfmt->Bmask,
225 SDL_GetVideoInfo()->vfmt->Amask );
226 break;
227 default:
228 // eg: dummy vid driver reports 8bpp
229 m_state = SDL_CreateRGBSurface( SDL_SWSURFACE, w, h, 32,
230 0xFF0000, 0x00FF00, 0x0000FF, 0xFF000000 );
231 break;
232 }
233 resetClip();
234 }
235
236
Canvas(State state)237 Canvas::Canvas( State state )
238 : m_state(state),
239 m_bgColour(0),
240 m_bgImage(NULL)
241 {
242 resetClip();
243 }
244
~Canvas()245 Canvas::~Canvas()
246 {
247 }
248
width() const249 int Canvas::width() const
250 {
251 return SURFACE(this)->w;
252 }
253
height() const254 int Canvas::height() const
255 {
256 return SURFACE(this)->h;
257 }
258
makeColour(int r,int g,int b) const259 int Canvas::makeColour( int r, int g, int b ) const
260 {
261 return SDL_MapRGB( SURFACE(this)->format, r, g, b );
262 }
263
makeColour(int c) const264 int Canvas::makeColour( int c ) const
265 {
266 return SDL_MapRGB( SURFACE(this)->format,
267 (c>>16)&0xff, (c>>8)&0xff, (c>>0)&0xff );
268 }
269
resetClip()270 void Canvas::resetClip()
271 {
272 if ( m_state ) {
273 setClip( 0, 0, width(), height() );
274 } else {
275 setClip( 0, 0, 0, 0 );
276 }
277 }
278
setClip(int x,int y,int w,int h)279 void Canvas::setClip( int x, int y, int w, int h )
280 {
281 m_clip = Rect(x,y,x+w-1,y+h-1);
282 }
283
setBackground(int c)284 void Canvas::setBackground( int c )
285 {
286 m_bgColour = c;
287 }
288
setBackground(Canvas * bg)289 void Canvas::setBackground( Canvas* bg )
290 {
291 m_bgImage = bg;
292 }
293
clear()294 void Canvas::clear()
295 {
296 if ( m_bgImage ) {
297 SDL_BlitSurface( SURFACE(m_bgImage), NULL, SURFACE(this), NULL );
298 } else {
299 SDL_FillRect( SURFACE(this), NULL, m_bgColour );
300 }
301 }
302
fade(const Rect & rr)303 void Canvas::fade( const Rect& rr )
304 {
305 Uint32 bpp;
306 Rect r = rr;
307 r.clipTo( m_clip );
308 bpp = SURFACE(this)->format->BytesPerPixel;
309 char* row = (char*)SURFACE(this)->pixels;
310 int pixStride = width();
311 int w = r.br.x - r.tl.x + 1;
312 int h = r.br.y - r.tl.y + 1;
313 row += (r.tl.x + r.tl.y * pixStride) * bpp;
314
315 SDL_LockSurface(SURFACE(this));
316 switch ( bpp ) {
317 case 2:
318 for ( int r=h; r>0; r-- ) {
319 for ( int i=0;i<w;i++) {
320 ((Uint16*)row)[i] = (((Uint16*)row)[i]>>1) & 0x7bef;
321 }
322 row += pixStride * bpp;
323 }
324 break;
325 case 4:
326 for ( int r=h; r>0; r-- ) {
327 for ( int i=0;i<w;i++) {
328 ((Uint32*)row)[i] = (((Uint32*)row)[i]>>1) & 0x7f7f7f;
329 }
330 row += pixStride * bpp;
331 }
332 break;
333 }
334 SDL_UnlockSurface(SURFACE(this));
335 }
336
scale(int factor) const337 Canvas* Canvas::scale( int factor ) const
338 {
339 Canvas *c = new Canvas( width()/factor, height()/factor );
340 if ( c ) {
341 if ( factor==4 && SURFACE(this)->format->BytesPerPixel==2 ) {
342 const uint16 MASK2LSB = 0xe79c;
343 int dpitch = SURFACE(c)->pitch / sizeof(uint16_t);
344 int spitch = SURFACE(this)->pitch / sizeof(uint16_t);
345 uint16_t *drow = (uint16_t*)SURFACE(c)->pixels;
346 for ( int y=0;y<c->height();y++ ) {
347 for ( int x=0;x<c->width();x++ ) {
348 uint16 p = 0;
349 uint16_t *srow = (uint16_t*)SURFACE(this)->pixels
350 + (y*spitch+x)*factor;
351 for ( int yy=0;yy<factor;yy++ ) {
352 uint16 q = 0;
353 for ( int xx=0;xx<factor;xx++ ) {
354 q += (srow[xx]&MASK2LSB)>>2;
355 }
356 p += (q&MASK2LSB)>>2;
357 srow += spitch;
358 }
359 drow[x] = p;
360 }
361 drow += dpitch;
362 }
363 } else {
364 for ( int y=0;y<c->height();y++ ) {
365 for ( int x=0;x<c->width();x++ ) {
366 int r=0,g=0,b=0;
367 Uint8 rr,gg,bb;
368 for ( int yy=0;yy<factor;yy++ ) {
369 for ( int xx=0;xx<factor;xx++ ) {
370 SDL_GetRGB( readPixel( x*factor+xx, y*factor+yy ),
371 SURFACE(this)->format, &rr,&gg,&bb );
372 r += rr;
373 g += gg;
374 b += bb;
375 }
376 }
377 int div = factor*factor;
378 c->drawPixel( x, y, makeColour(r/div,g/div,b/div) );
379 }
380 }
381 }
382 }
383 return c;
384 }
385
386
scale(int w,int h)387 void Canvas::scale( int w, int h )
388 {
389 if ( w!=width() && h!=height() ) {
390 SDL_Surface *s = zoomSurface( SURFACE(this),
391 (double)w/(double)width(),
392 (double)h/(double)height() );
393 if ( s ) {
394 SDL_FreeSurface( SURFACE(this) );
395 m_state = s;
396 }
397 }
398 }
399
400
clear(const Rect & r)401 void Canvas::clear( const Rect& r )
402 {
403 if ( m_bgImage ) {
404 SDL_Rect srcRect = { r.tl.x, r.tl.y, r.br.x-r.tl.x+1, r.br.y-r.tl.y+1 };
405 SDL_BlitSurface( SURFACE(m_bgImage), &srcRect, SURFACE(this), &srcRect );
406 } else {
407 drawRect( r, m_bgColour );
408 }
409 }
410
drawImage(Canvas * canvas,int x,int y)411 void Canvas::drawImage( Canvas *canvas, int x, int y )
412 {
413 SDL_Rect dest = { x, y, 0, 0 };
414 SDL_BlitSurface( SURFACE(canvas), NULL, SURFACE(this), &dest );
415 }
416
drawPixel(int x,int y,int c)417 void Canvas::drawPixel( int x, int y, int c )
418 {
419 Uint32 bpp, ofs;
420
421 bpp = SURFACE(this)->format->BytesPerPixel;
422 ofs = SURFACE(this)->pitch*y;
423 char* row = (char*)SURFACE(this)->pixels + ofs;
424
425 SDL_LockSurface(SURFACE(this));
426 switch ( bpp ) {
427 case 2: ((Uint16*)row)[x] = c; break;
428 case 4: ((Uint32*)row)[x] = c; break;
429 }
430 SDL_UnlockSurface(SURFACE(this));
431 }
432
readPixel(int x,int y) const433 int Canvas::readPixel( int x, int y ) const
434 {
435 Uint32 bpp, ofs;
436 int c;
437
438 bpp = SURFACE(this)->format->BytesPerPixel;
439 ofs = SURFACE(this)->pitch*y;
440 char* row = (char*)SURFACE(this)->pixels + ofs;
441
442 SDL_LockSurface(SURFACE(this));
443 switch ( bpp ) {
444 case 2: c = ((Uint16*)row)[x]; break;
445 case 4: c = ((Uint32*)row)[x]; break;
446 default: c=0; break;
447 }
448 SDL_UnlockSurface(SURFACE(this));
449 return c;
450 }
451
drawLine(int x1,int y1,int x2,int y2,int color)452 void Canvas::drawLine( int x1, int y1, int x2, int y2, int color )
453 {
454 int lg_delta, sh_delta, cycle, lg_step, sh_step;
455 lg_delta = x2 - x1;
456 sh_delta = y2 - y1;
457 lg_step = Sgn(lg_delta);
458 lg_delta = Abs(lg_delta);
459 sh_step = Sgn(sh_delta);
460 sh_delta = Abs(sh_delta);
461 if (sh_delta < lg_delta) {
462 cycle = lg_delta >> 1;
463 while (x1 != x2) {
464 drawPixel( x1, y1, color);
465 cycle += sh_delta;
466 if (cycle > lg_delta) {
467 cycle -= lg_delta;
468 y1 += sh_step;
469 }
470 x1 += lg_step;
471 }
472 drawPixel( x1, y1, color);
473 }
474 cycle = sh_delta >> 1;
475 while (y1 != y2) {
476 drawPixel( x1, y1, color);
477 cycle += lg_delta;
478 if (cycle > sh_delta) {
479 cycle -= sh_delta;
480 x1 += lg_step;
481 }
482 y1 += sh_step;
483 }
484 drawPixel( x1, y1, color);
485 }
486
drawPath(const Path & path,int color,bool thick)487 void Canvas::drawPath( const Path& path, int color, bool thick )
488 {
489 // allow for thick lines in clipping
490 Rect clip = m_clip;
491 clip.tl.x++; clip.tl.y++;
492 clip.br.x--; clip.br.y--;
493
494 int i=0;
495 const int n = path.numPoints();
496
497 for ( ; i<n && !clip.contains( path.point(i) ); i++ ) {
498 //skip clipped start pt
499 }
500 i++;
501 SDL_LockSurface(SURFACE(this));
502 for ( ; i<n; i++ ) {
503 // pt i-1 is guranteed to be inside clipping
504 const Vec2& p2 = path.point(i);
505 if ( clip.contains( p2 ) ) {
506 const Vec2& p1 = path.point(i-1);
507 switch ( SURFACE(this)->format->BytesPerPixel ) {
508 case 2:
509 if ( thick ) {
510 renderLine<Uint16,3>( SURFACE(this)->pixels,
511 SURFACE(this)->pitch,
512 p1.x, p1.y, p2.x, p2.y, color );
513 } else {
514 renderLine<Uint16,1>( SURFACE(this)->pixels,
515 SURFACE(this)->pitch,
516 p1.x, p1.y, p2.x, p2.y, color );
517 }
518 break;
519 case 4:
520 if ( thick ) {
521 renderLine<Uint32,3>( SURFACE(this)->pixels,
522 SURFACE(this)->pitch,
523 p1.x, p1.y, p2.x, p2.y, color );
524 } else {
525 renderLine<Uint32,1>( SURFACE(this)->pixels,
526 SURFACE(this)->pitch,
527 p1.x, p1.y, p2.x, p2.y, color );
528 }
529 break;
530 }
531 } else {
532 for ( ; i<n && !clip.contains( path.point(i) ); i++ ) {
533 //skip until we find a unclipped pt - this will be p1 next
534 //time around
535 }
536 }
537 }
538 SDL_UnlockSurface(SURFACE(this));
539
540 }
541
drawRect(int x,int y,int w,int h,int c,bool fill)542 void Canvas::drawRect( int x, int y, int w, int h, int c, bool fill )
543 {
544 if ( fill ) {
545 SDL_Rect r = { x, y, w, h };
546 SDL_FillRect( SURFACE(this), &r, c );
547 } else {
548 SDL_Rect f = { x, y, w, h };
549 SDL_Rect r;
550 r=f; r.h=1; SDL_FillRect( SURFACE(this), &r, c );
551 r.y+=f.h-1; SDL_FillRect( SURFACE(this), &r, c );
552 r=f; r.w=1; SDL_FillRect( SURFACE(this), &r, c );
553 r.x+=f.w-1; SDL_FillRect( SURFACE(this), &r, c );
554 }
555 }
556
drawRect(const Rect & r,int c,bool fill)557 void Canvas::drawRect( const Rect& r, int c, bool fill )
558 {
559 drawRect( r.tl.x, r.tl.y, r.br.x-r.tl.x, r.br.y-r.tl.y, c, fill );
560 }
561
562
563
Window(int w,int h,const char * title,const char * winclass)564 Window::Window( int w, int h, const char* title, const char* winclass )
565 {
566 if ( winclass ) {
567 char s[80];
568 snprintf(s,80,"SDL_VIDEO_X11_WMCLASS=%s",winclass);
569 putenv(s);
570 }
571 if ( title ) {
572 SDL_WM_SetCaption( title, title );
573 }
574 #ifdef USE_HILDON
575 m_state = SDL_SetVideoMode( w, h, 16, SDL_SWSURFACE);//SDL_FULLSCREEN);
576 SDL_WM_ToggleFullScreen( SURFACE(this) );
577 SDL_ShowCursor( SDL_DISABLE );
578 #else
579 m_state = SDL_SetVideoMode( w, h, 0, SDL_SWSURFACE);
580 #endif
581 if ( SURFACE(this) == NULL ) {
582 throw "Unable to set video mode";
583 }
584 resetClip();
585
586 #ifdef USE_HILDON
587 SDL_SysWMinfo sys;
588 SDL_VERSION( &sys.version );
589 SDL_GetWMInfo( &sys );
590 printf("X11 window =%08x\n",sys.info.x11.window);
591 printf("X11 fswindow =%08x\n",sys.info.x11.fswindow);
592 printf("X11 wmwindow =%08x\n",sys.info.x11.wmwindow);
593
594 uint32_t pid = getpid();
595 XChangeProperty( sys.info.x11.display,
596 sys.info.x11.wmwindow,
597 XInternAtom (sys.info.x11.display, "_NET_WM_PID", False),
598 XA_CARDINAL, 32, PropModeReplace,
599 (unsigned char*)&pid, 1 );
600 #endif
601 }
602
603
update(const Rect & r)604 void Window::update( const Rect& r )
605 {
606 if ( r.tl.x < width() && r.tl.y < height() ) {
607 int x1 = Max( 0, r.tl.x );
608 int y1 = Max( 0, r.tl.y );
609 int x2 = Min( width()-1, r.br.x );
610 int y2 = Min( height()-1, r.br.y );
611 int w = Max( 0, x2-x1 );
612 int h = Max( 0, y2-y1 );
613 if ( w > 0 && h > 0 ) {
614 SDL_UpdateRect( SURFACE(this), x1, y1, w, h );
615 }
616 }
617 }
618
raise()619 void Window::raise()
620 {
621 SDL_SysWMinfo sys;
622 SDL_VERSION( &sys.version );
623 SDL_GetWMInfo( &sys );
624
625 #ifndef WIN32
626 // take focus...
627 XEvent ev = { 0 };
628 ev.xclient.type = ClientMessage;
629 ev.xclient.window = sys.info.x11.wmwindow;
630 ev.xclient.message_type = XInternAtom (sys.info.x11.display,
631 "_NET_ACTIVE_WINDOW", False);
632 ev.xclient.format = 32;
633 //all xewv.xclient.data==0 -> older spec?
634
635 XSendEvent (sys.info.x11.display,
636 DefaultRootWindow(sys.info.x11.display),
637 False,
638 NoEventMask, //SubstructureRedirectMask,
639 &ev);
640 XSync( sys.info.x11.display, False );
641 #endif
642 //XRaiseWindow( sys.info.x11.display, sys.info.x11.window );
643 }
644
645
setSubName(const char * sub)646 void Window::setSubName( const char *sub )
647 {
648 #ifdef USE_HILDON
649 SDL_SysWMinfo sys;
650 SDL_VERSION( &sys.version );
651 SDL_GetWMInfo( &sys );
652
653 XChangeProperty( sys.info.x11.display,
654 sys.info.x11.fswindow,
655 XInternAtom (sys.info.x11.display, "_MB_WIN_SUB_NAME", False),
656 XA_STRING, 8, PropModeReplace,
657 (unsigned char*)sub, strlen(sub) );
658 #endif
659 }
660
661
Image(const char * file,bool alpha)662 Image::Image( const char* file, bool alpha )
663 {
664 alpha = false;
665 std::string f( "data/" );
666 SDL_Surface* img = IMG_Load((f+file).c_str());
667 if ( !img ) {
668 f = std::string( DEFAULT_RESOURCE_PATH "/" );
669 img = IMG_Load((f+file).c_str());
670 }
671 if ( img ) {
672 printf("loaded image %s\n",(f+file).c_str());
673 if ( alpha ) {
674 m_state = SDL_DisplayFormatAlpha( img );
675 } else {
676 m_state = SDL_DisplayFormat( img );
677 // SDL_SetColorKey( SURFACE(this),
678 // SDL_SRCCOLORKEY|SDL_RLEACCEL,
679 // makeColour( 0x00ff00ff ) );
680 }
681 if ( m_state ) {
682 SDL_FreeSurface( img );
683 } else {
684 printf("warning image %s not converted to display format\n",(f+file).c_str());
685 m_state = img;
686 }
687 } else {
688 throw "image not found";
689 }
690 resetClip();
691 }
692
693
694
writeBMP(const char * filename) const695 int Canvas::writeBMP( const char* filename ) const
696 {
697 typedef struct {
698 unsigned short int type; /* Magic identifier */
699 unsigned int size; /* File size in bytes */
700 unsigned short int reserved1, reserved2;
701 unsigned int offset; /* Offset to image data, bytes */
702 } BMPHEADER;
703
704 typedef struct {
705 unsigned int size; /* Header size in bytes */
706 int width,height; /* Width and height of image */
707 unsigned short int planes; /* Number of colour planes */
708 unsigned short int bits; /* Bits per pixel */
709 unsigned int compression; /* Compression type */
710 unsigned int imagesize; /* Image size in bytes */
711 int xresolution,yresolution; /* Pixels per meter */
712 unsigned int ncolours; /* Number of colours */
713 unsigned int importantcolours; /* Important colours */
714 } BMPINFOHEADER;
715
716 int w = width();
717 int h = height();
718 BMPHEADER head = { 'B'|('M'<<8), 14+40+w*h*3, 0, 0, 0 };
719 BMPINFOHEADER info = { 40, w, h, 1, 24, 0, w*h*3, 100, 100, 0, 0 };
720
721 FILE *f = fopen( filename, "wb" );
722 if ( f ) {
723 Uint32 bpp;
724 bpp = SURFACE(this)->format->BytesPerPixel;
725
726 fwrite( &head, 14, 1, f );
727 fwrite( &info, 40, 1, f );
728 for ( int y=h-1; y>=0; y-- ) {
729 for ( int x=0; x<w; x++ ) {
730 int p = readPixel( x, y );
731 if ( bpp==2 ) {
732 p = R16G16B16_TO_RGB888( R16(p), G16(p), B16(p) );
733 }
734 fwrite( &p, 3, 1, f );
735 }
736 }
737 fclose(f);
738 return 1;
739 }
740 return 0;
741 }
742