1 /******************************************************************************************
2 *
3 * HighNoon - Duell im All
4 * Copyright (c) 2005, 2006 Patrick Gerdsmeier <patrick@gerdsmeier.net>
5 *
6 * "graphics.cpp"
7 *
8 *
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
13 * any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 *
24 ******************************************************************************************/
25
26 #include <iostream>
27 #include <stdio.h>
28 #include <cmath>
29
30 #include <SDL_image.h>
31
32 #include "graphics.hpp"
33
34 /******************************************************************************************
35 *
36 * Font
37 *
38 ******************************************************************************************/
Font()39 Font::Font()
40 {
41 verbose( "Initializing Font" );
42
43 if ( ( font_image=IMG_Load( (char*)"/usr/local/share/highmoon/gfx/font.gif" ) ) == NULL ) {
44 std::cout << "Error in Font: " << SDL_GetError() << std::endl;
45 exit(1);
46 }
47
48 if ( SCREENFACTOR != 1 )
49 font_image = Sprite::zoom(font_image, SCREENFACTOR);
50
51 SDL_SetColorKey( font_image,
52 SDL_RLEACCEL | SDL_SRCCOLORKEY,
53 SDL_MapRGB( font_image->format, 255, 0, 255 ) );
54 font_image = SDL_DisplayFormat(font_image);
55
56 // From SPACE
57 int font_sizes[] = {
58 3, 2, 4, 0, 6, 0, 0, 2, 3, 3, 0, 6, 2, 5, 2, 0,
59 6, 3, 6, 5, 6, 6, 6, 6, 6, 6, 2, 2, 0, 0, 0, 5,
60 6, 6, 6, 6, 6, 6, 5, 6, 6, 2, 5, 6, 5, 8, 6, 6,
61 6, 6, 5, 6, 6, 6, 6, 8, 6, 6, 6, 0, 0, 0, 0, 0,
62 0, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 6, 6, 6, 7,
63 6, 6, 6, 6, 6, 8, 8, 5, 6, 6, 6, 5, 6, 5, 0, 0
64 };
65 double p = 0;
66
67 // Create Width- and Position-Table
68 for ( int i=0; i < 96; i++ ) {
69 font_pos[i] = (int)p;
70 font_width[i] = (int)( font_sizes[i] * 4 * SCREENFACTOR );
71 p += ( i==0 ) ? 0 : font_sizes[i] * 4 * SCREENFACTOR;
72 }
73 }
74
~Font()75 Font::~Font()
76 {
77 verbose( "Deleting Font" );
78
79 SDL_FreeSurface(font_image);
80 }
81
getLineHeight() const82 int Font::getLineHeight() const
83 {
84 return font_image->h + 4;
85 }
86
print(int x,int y,std::string txt,int alpha)87 void Font::print( int x, int y, std::string txt, int alpha )
88 {
89 src.y = 0;
90 src.h = dst.h = font_image->h;
91 dst.y = y;
92 dst.x = x;
93
94 SDL_SetAlpha( font_image, SDL_SRCALPHA, alpha );
95
96 for ( int i=0; i < (int)txt.length(); i++ ) {
97 int srcp = (int)txt[i]-32;
98
99 if ( srcp != 0 ) {
100 src.x = font_pos[srcp];
101 src.w = dst.w = font_width[srcp];
102
103 if ( dst.x > SCREENWIDTH || dst.y > SCREENHEIGHT )
104 break;
105
106 if ( dst.x + dst.w >= 0 && dst.y + dst.h >= 0 && src.w > 0 )
107 SDL_BlitSurface( font_image, &src, MYSDLSCREEN, &dst );
108
109 }
110 x += font_width[srcp];
111 dst.x = x;
112 }
113 }
114
getWidth(std::string txt)115 int Font::getWidth( std::string txt )
116 {
117 int s = 0;
118
119 for ( int i=0; i < (int)txt.length(); i++ ) {
120 int t = (int)txt[i]-32;
121
122 s += font_width[t];
123 }
124
125 return s;
126 }
127
128 /******************************************************************************************
129 *
130 * Sprite
131 *
132 ******************************************************************************************/
Sprite(char * filename,int frames)133 Sprite::Sprite( char* filename, int frames ) :
134 x(0),
135 y(0),
136 alpha(255),
137 repeat_mode(true),
138 frames(frames),
139 actual_frame(0),
140 frame_delay(ANIMFRAME),
141 frame_rate(ANIMFRAME)
142 {
143 verbose( "Initializing Sprite: " + std::string(filename) );
144
145 if ( ( sprite_image = IMG_Load( filename ) ) == NULL ) {
146 std::cout << "Error in Sprite: " << SDL_GetError() << std::endl;
147 exit(1);
148 }
149
150 if ( SCREENFACTOR != 1 )
151 sprite_image = Sprite::zoom(sprite_image, SCREENFACTOR);
152
153 SDL_SetColorKey( sprite_image,
154 SDL_RLEACCEL | SDL_SRCCOLORKEY,
155 SDL_MapRGB( sprite_image->format, 255, 0, 255 ) );
156 sprite_image = SDL_DisplayFormat(sprite_image);
157
158 width = sprite_image->w / frames;
159 height = sprite_image->h;
160 }
161
~Sprite()162 Sprite::~Sprite()
163 {
164 verbose( "Deleting Sprite" );
165
166 SDL_FreeSurface( sprite_image );
167 }
168
setOffset(int x,int y)169 void Sprite::setOffset( int x, int y )
170 {
171 x_offset = x;
172 y_offset = y;
173 }
174
is_onLastFrame()175 bool Sprite::is_onLastFrame()
176 {
177 return ( actual_frame == frames-1 && frame_delay == 0 ) ? true : false;
178 }
179
getWidth()180 int Sprite::getWidth()
181 {
182 return width;
183 }
184
setFramerate(int rate)185 void Sprite::setFramerate( int rate )
186 {
187 frame_rate = rate;
188 frame_delay = rate;
189 }
190
setRepeatmode(bool mode)191 void Sprite::setRepeatmode( bool mode )
192 {
193 repeat_mode = mode;
194 }
195
resetFrames()196 void Sprite::resetFrames()
197 {
198 actual_frame = 0;
199 }
200
setPos(int x,int y)201 void Sprite::setPos( int x, int y )
202 {
203 this->x = x;
204 this->y = y;
205 }
206
setAlpha(int alpha)207 void Sprite::setAlpha( int alpha )
208 {
209 this->alpha = alpha;
210 }
211
draw()212 void Sprite::draw()
213 {
214 rect.x = x + x_offset - width/2;
215 rect.y = y + y_offset - width/2;
216 rect.w = width;
217 rect.h = height;
218 sprite_rect.x = actual_frame * width;
219 sprite_rect.y = 0;
220 sprite_rect.w = width;
221 sprite_rect.h = height;
222
223 SDL_SetAlpha( sprite_image, SDL_SRCALPHA, alpha);
224 SDL_BlitSurface( sprite_image, &sprite_rect, MYSDLSCREEN, &rect );
225
226 if ( frame_delay-- < 1 ) {
227 frame_delay = frame_rate;
228
229 if ( ++actual_frame >= frames ) {
230
231 if (repeat_mode)
232 actual_frame = 0;
233 else
234 actual_frame = frames-1;
235 }
236 }
237 }
238
putpixel(int x,int y,Uint32 pixel,SDL_Surface * screen)239 void Sprite::putpixel( int x, int y, Uint32 pixel, SDL_Surface *screen )
240 {
241 // NOTE: The surface must be locked before calling this!
242 if ( x >= 0 && x < SCREENWIDTH && y >= 0 && y < SCREENHEIGHT) {
243
244 int bpp = screen->format->BytesPerPixel;
245 /* Here p is the address to the pixel we want to set */
246 Uint8 *p = (Uint8 *)screen->pixels + y * screen->pitch + x * bpp;
247
248 switch(bpp) {
249 case 1:
250 *p = pixel;
251 break;
252
253 case 2:
254 *(Uint16 *)p = pixel;
255 break;
256
257 case 3:
258 if( SDL_BYTEORDER == SDL_BIG_ENDIAN ) {
259 p[0] = (pixel >> 16) & 0xff;
260 p[1] = (pixel >> 8) & 0xff;
261 p[2] = pixel & 0xff;
262 } else {
263 p[0] = pixel & 0xff;
264 p[1] = (pixel >> 8) & 0xff;
265 p[2] = (pixel >> 16) & 0xff;
266 }
267 break;
268
269 case 4:
270 *(Uint32 *)p = pixel;
271 break;
272 }
273 }
274 }
275
get_distance(double x,double y)276 double get_distance( double x, double y )
277 {
278 double xx=x-rint(x);
279 double yy=y-rint(y);
280
281 return sqrt( xx*xx + yy*yy );
282 }
283
get_PixelColor(double x,double y,SDL_Surface * surface,SDL_Color & pixel_color)284 void get_PixelColor( double x, double y, SDL_Surface *surface, SDL_Color &pixel_color )
285 {
286 int bpp = surface->format->BytesPerPixel;
287 int xxx = (int)x * bpp;
288 int yyy = (int)y * surface->pitch;
289 Uint8 index = *( (Uint8 *)surface->pixels + xxx + yyy );
290 SDL_Color *pix_color = surface->format->palette->colors + index;
291
292 // Check for Background-color
293 if ( pix_color->r == 255 && pix_color->g == 0 && pix_color->b ==255 ) {
294 pixel_color.r=0;
295 pixel_color.g=0;
296 pixel_color.b=30;
297 } else {
298 pixel_color.r=pix_color->r;
299 pixel_color.g=pix_color->g;
300 pixel_color.b=pix_color->b;
301 }
302 }
303
bicubical(double x,double y,SDL_Surface * surface,SDL_Color & pixel_color)304 void bicubical( double x, double y, SDL_Surface *surface, SDL_Color &pixel_color )
305 {
306 double cnt = 0;
307 double r = 0, g = 0, b = 0;
308 SDL_Color color;
309
310 if ( y-1 >=0 ) {
311
312 if ( x-1 >= 0 ) {
313 cnt += 0.25;
314 get_PixelColor( x-1, y-1, surface, color );
315 r += color.r * 0.25;
316 g += color.g * 0.25;
317 b += color.b * 0.25;
318 }
319
320 cnt += 0.5;
321 get_PixelColor( x, y-1, surface, color );
322 r += color.r * 0.5;
323 g += color.g * 0.5;
324 b += color.b * 0.5;
325
326 if ( x+1 < surface->w ) {
327 cnt += 0.25;
328 get_PixelColor( x+1, y-1, surface, color );
329 r += color.r * 0.25;
330 g += color.g * 0.25;
331 b += color.b * 0.25;
332 }
333 }
334
335 if ( x-1 >= 0 ) {
336 cnt += 0.5;
337 get_PixelColor( x-1, y, surface, color );
338 r += color.r * 0.5;
339 g += color.g * 0.5;
340 b += color.b * 0.5;
341 }
342
343 cnt += 1;
344 get_PixelColor( x, y, surface, color );
345 r += color.r;
346 g += color.g;
347 b += color.b;
348
349 if ( x+1 < surface->w ) {
350 cnt += 0.5;
351 get_PixelColor( x+1, y, surface, color );
352 r += color.r * 0.5;
353 g += color.g * 0.5;
354 b += color.b * 0.5;
355 }
356
357 if ( y+1 < surface->w ) {
358
359 if ( x-1 >= 0 ) {
360 cnt += 0.25;
361 get_PixelColor( x-1, y+1, surface, color );
362 r += color.r * 0.25;
363 g += color.g * 0.25;
364 b += color.b * 0.25;
365 }
366
367 cnt += 0.5;
368 get_PixelColor( x, y+1, surface, color );
369 r += color.r * 0.5;
370 g += color.g * 0.5;
371 b += color.b * 0.5;
372
373 if ( x+1 < surface->w ) {
374 cnt += 0.25;
375 get_PixelColor( x+1, y+1, surface, color );
376 r += color.r * 0.25;
377 g += color.g * 0.25;
378 b += color.b * 0.25;
379 }
380 }
381
382 // Restore Background-color
383 r /= cnt;
384 g /= cnt;
385 b /= cnt;
386
387 if ( r < 1 && g < 1 && b <= 30 ) {
388 pixel_color.r = 255;
389 pixel_color.g = 0;
390 pixel_color.b = 255;
391 } else {
392 pixel_color.r = (int)r;
393 pixel_color.g = (int)g;
394 pixel_color.b = (int)b;
395 }
396 }
397
zoom(SDL_Surface * surface,double factor)398 SDL_Surface *Sprite::zoom( SDL_Surface *surface, double factor )
399 {
400 int width = surface->w;
401 int height = surface->h;
402
403 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
404 Uint32 rmask = 0xff000000;
405 Uint32 gmask = 0x00ff0000;
406 Uint32 bmask = 0x0000ff00;
407 Uint32 amask = 0x000000ff;
408 #else
409 Uint32 rmask = 0x000000ff;
410 Uint32 gmask = 0x0000ff00;
411 Uint32 bmask = 0x00ff0000;
412 Uint32 amask = 0xff000000;
413 #endif
414
415 int z_width = (int)(width*factor);
416 int z_height = (int)(height*factor);
417 SDL_Surface *zoom_surface = SDL_CreateRGBSurface( SDL_HWSURFACE | SDL_SRCCOLORKEY, z_width, z_height, 32, rmask, gmask, bmask, amask );
418
419 SDL_LockSurface(surface);
420 SDL_LockSurface(zoom_surface);
421
422 for ( int xx=0; xx < z_width; xx++ ) {
423
424 for ( int yy=0; yy < z_height; yy++ ) {
425 SDL_Color color;
426 bicubical( (double)xx/factor, (double)yy/factor, surface, color );
427 Sprite::putpixel( xx, yy, SDL_MapRGB( zoom_surface->format, color.r, color.g, color.b ), zoom_surface );
428 }
429 }
430
431 SDL_UnlockSurface(surface);
432 SDL_UnlockSurface(zoom_surface);
433
434 return zoom_surface;
435 }
436
437 int Sprite::x_offset = 0;
438 int Sprite::y_offset = 0;
439
440 /******************************************************************************************
441 *
442 * Star
443 *
444 ******************************************************************************************/
Star()445 Star::Star()
446 :
447 x(rx()),
448 y(ry()),
449 b(blink()),
450 c(color())
451 {}
452
draw()453 void Star::draw()
454 {
455 if ( b-- == 0 ) b=blink();
456
457 if ( b>5 ) {
458 Sprite::putpixel( x, y, SDL_MapRGB( MYSDLSCREEN->format, c, c, c ));
459
460 if ( c>200 ) {
461 Sprite::putpixel( x+1, y, SDL_MapRGB( MYSDLSCREEN->format, c/2, c/2, c/2 ));
462 Sprite::putpixel( x+1, y+1, SDL_MapRGB( MYSDLSCREEN->format, c/2, c/2, c/2 ));
463 Sprite::putpixel( x, y+1, SDL_MapRGB( MYSDLSCREEN->format, c/2, c/2, c/2 ));
464 }
465 }
466 }
467
rx()468 int Star::rx()
469 {
470 return (int)RANDOM( SCREENWIDTH-20, 20);
471 }
472
ry()473 int Star::ry()
474 {
475 return (int)RANDOM( SCREENHEIGHT-20, 20);
476 }
477
color()478 int Star::color()
479 {
480 return (int)RANDOM( 245,25 );
481 }
482
blink()483 int Star::blink()
484 {
485 return (int)RANDOM( 2000,1 );
486 }
487
488 /******************************************************************************************
489 *
490 * Shooting-Star
491 *
492 ******************************************************************************************/
Shootingstar()493 Shootingstar::Shootingstar()
494 :
495 x(rx()),
496 y(ry()),
497 s(speed()),
498 w(wait())
499 {}
500
draw()501 void Shootingstar::draw()
502 {
503 if ( w-- == 0 ) {
504 w = wait();
505 x = rx();
506 y = ry();
507 s = speed();
508 }
509
510 double as=( s < 0 )? -s : s;
511
512 if ( w<40 ) {
513
514 for ( int i=0; i < 10; i++ ) {
515 int c = (int)(((double)w)/40*(i*25));
516 if (i == 9) c +=10;
517 int x = (int)(this->x + s * i);
518 int y = (int)(this->y + as * i);
519 Sprite::putpixel( x, y, SDL_MapRGB( MYSDLSCREEN->format, c, c, c + 20 ));
520 }
521 x += s * 4;
522 y += as * 4;
523 }
524 }
525
rx()526 double Shootingstar::rx()
527 {
528 return (int)RANDOM( SCREENWIDTH-200, 200);
529 }
530
ry()531 double Shootingstar::ry()
532 {
533 return (int)RANDOM( SCREENHEIGHT-200, 100);
534 }
535
speed()536 double Shootingstar::speed()
537 {
538 return ( (int)RANDOM(2,0)==1 ) ? 1 : -1;
539 }
540
wait()541 int Shootingstar::wait()
542 {
543 return (int)RANDOM(2000,1000);
544 }
545
546 /******************************************************************************************
547 *
548 * Goldrain
549 *
550 ******************************************************************************************/
Goldrain()551 Goldrain::Goldrain()
552 :
553 x((double)rx()),
554 y((double)ry()),
555 sp(speed()),
556 xoffset(0),
557 yoffset(0),
558 b(blink()),
559 cr(0),
560 cg(0),
561 cb(0)
562 {
563 switch ((int)RANDOM(4,0)) {
564
565 case 0:
566 cr = color();
567 break;
568
569 case 1:
570 cg = color();
571 break;
572
573 case 2:
574 cg = cr = color();
575 break;
576
577 default:
578 cb = color();
579 }
580 }
581
setOffset(int x,int y)582 void Goldrain::setOffset(int x, int y)
583 {
584 xoffset = (double)x;
585 yoffset = (double)y;
586 }
587
draw()588 void Goldrain::draw()
589 {
590 if ( (y += sp ) > 100 ) {
591 y -= 100;
592 x = (double)rx();
593 }
594
595 x += (int)( 4 * (rand()/(RAND_MAX+1.0) ) -2 );
596
597 if ( b-- == 0 )
598 b = blink();
599 else if ( b > 1 && y >= 0 ) {
600 int r = (int)( cr*y/110 ) + 40;
601 int g = (int)( cg*y/110 ) + 40;
602 int b = (int)( cb*y/110 ) + 40;
603
604 Sprite::putpixel( (int)(x+xoffset), (int)(y+yoffset), SDL_MapRGB( MYSDLSCREEN->format, r, g, b ) );
605
606 if ( r > 150 || g > 150 || b > 130 )
607 Sprite::putpixel( (int)(x+xoffset+1), (int)(y + yoffset), SDL_MapRGB( MYSDLSCREEN->format, r/2, g/2, b/2 ) );
608
609 if ( r > 170 || g > 170 || b > 150 )
610 Sprite::putpixel( (int)(x+xoffset), (int)(y + yoffset + 1), SDL_MapRGB( MYSDLSCREEN->format, r/2, g/2, b/2 ) );
611
612 if ( r > 200 || g > 200 || b > 180 )
613 Sprite::putpixel( (int)(x+xoffset+1), (int)(y + yoffset + 1), SDL_MapRGB( MYSDLSCREEN->format, r/2, g/2, b/2 ) );
614 }
615 }
616
rx()617 double Goldrain::rx()
618 {
619 return RANDOM( 40,-40 );
620 }
621
ry()622 double Goldrain::ry()
623 {
624 return RANDOM( 100,0 );
625 }
626
speed()627 double Goldrain::speed()
628 {
629 return RANDOM( 2,1 );
630 }
631
color()632 int Goldrain::color()
633 {
634 return (int)RANDOM( 255, 100 );
635 }
636
blink()637 int Goldrain::blink()
638 {
639 return (int)RANDOM( 10,0 );
640 }
641
642