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