1 /*
2     screen.c - Screen functions for Ballerburg
3 
4     Copyright (C) 2010, 2014  Thomas Huth
5 
6     This program is free software: you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation, either version 3 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <SDL.h>
24 
25 #include "i18n.h"
26 #include "screen.h"
27 #include "sdlgui.h"
28 #include "sdlgfx.h"
29 
30 #define min(a,b) ((a)<(b)?(a):(b))
31 #define max(a,b) ((a)>(b)?(a):(b))
32 
33 #if WITH_SDL2
34 
35 static SDL_Window *sdlWindow;
36 
37 #define USE_SDL2_RENDERER 0
38 #if USE_SDL2_RENDERER
39 static SDL_Renderer *sdlRenderer;
40 static SDL_Texture *sdlTexture;
41 #else
42 static SDL_Surface *windowSurf;
43 #endif
44 
45 #endif
46 
47 SDL_Surface *surf;
48 static Uint32 the_color, fill_color;
49 static Uint32 bg_color;
50 
51 static int fill_style, fill_interior;
52 
53 static SGOBJ donebuttondlg[] =
54 {
55 	{ SGBOX, 0, 0, 36,29, 8,1, NULL },
56 	{ SGBUTTON, SG_EXIT, 0, 0,0, 8,1, N_("Done") }
57 };
58 
59 #if WITH_SDL2
60 static int fullscreenflag = 0;
scr_sdl2_init(void)61 static void scr_sdl2_init(void)
62 {
63 	sdlWindow = SDL_CreateWindow("Ballerburg SDL",
64 	                             SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
65 	                             640, 480, fullscreenflag);
66 #if USE_SDL2_RENDERER
67 	sdlRenderer = SDL_CreateRenderer(sdlWindow, -1, 0);
68 	if (!sdlWindow || !sdlRenderer)
69 	{
70 		fprintf(stderr,"Failed to create window or renderer!\n");
71 		exit(-1);
72 	}
73 	SDL_RenderSetLogicalSize(sdlRenderer, 640, 480);
74 	sdlTexture = SDL_CreateTexture(sdlRenderer, SDL_PIXELFORMAT_RGB888,
75 					SDL_TEXTUREACCESS_STREAMING, 640, 480);
76 #else
77 	windowSurf = SDL_GetWindowSurface(sdlWindow);
78 #endif
79 }
80 #endif
81 
scr_init(void)82 void scr_init(void)
83 {
84 	if (SDL_Init(SDL_INIT_VIDEO) < 0)
85 	{
86 		fprintf(stderr, "Could not initialize the SDL library:\n %s\n",
87 			SDL_GetError() );
88 		exit(-1);
89 	}
90 
91 #if WITH_SDL2
92 	scr_sdl2_init();
93 	surf = SDL_CreateRGBSurface(SDL_SWSURFACE, 640, 480, 32, 0x00FF0000,
94 				    0x0000FF00, 0x000000FF, 0);
95 #else
96 	surf = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE);
97 	SDL_WM_SetCaption("Ballerburg SDL", "Ballerburg");
98 #endif
99 
100 	if (!surf)
101 	{
102 		fprintf(stderr, "Could not initialize the SDL library:\n %s\n",
103 			SDL_GetError() );
104 		exit(-1);
105 	}
106 
107 	bg_color = SDL_MapRGB(surf->format,0xe0,0xf0,0xff);
108 
109 	SDLGui_Init();
110 	SDLGui_SetScreen(surf);
111 }
112 
scr_exit(void)113 void scr_exit(void)
114 {
115 	SDLGui_UnInit();
116 
117 #if WITH_SDL2
118 	if (surf)
119 		SDL_FreeSurface(surf);
120 #if USE_SDL2_RENDERER
121 	if (sdlTexture)
122 		SDL_DestroyTexture(sdlTexture);
123 	if (sdlRenderer)
124 		SDL_DestroyRenderer(sdlRenderer);
125 #endif
126 	if (sdlWindow)
127 		SDL_DestroyWindow(sdlWindow);
128 #endif
129 	SDL_Quit();
130 }
131 
scr_togglefullscreen(void)132 void scr_togglefullscreen(void)
133 {
134 #if WITH_SDL2
135 #if USER_SDL2_RENDERER
136 	SDL_DestroyTexture(sdlTexture);
137 	SDL_DestroyRenderer(sdlRenderer);
138 	fullscreenflag ^= SDL_WINDOW_FULLSCREEN_DESKTOP;
139 #else
140 	fullscreenflag ^= SDL_WINDOW_FULLSCREEN;
141 #endif
142 	SDL_DestroyWindow(sdlWindow);
143 	scr_sdl2_init();
144 	SDL_UpdateRect(surf, 0, 0, 640, 480);
145 #else
146 	SDL_WM_ToggleFullScreen(surf);
147 #endif
148 }
149 
scr_clear(void)150 void scr_clear(void)
151 {
152 	SDL_Rect rect;
153 	Uint32 white;
154 	int i;
155 
156 	white = SDL_MapRGB(surf->format,0xff,0xff,0xff);
157 
158 	rect.x = 0;
159 	rect.y = 0;
160 	rect.w = 640;
161 	rect.h = 400;
162 	SDL_FillRect(surf, &rect, bg_color);
163 
164 	for (i = 0; i < 80; i += 1)
165 	{
166 		rect.x = 0;
167 		rect.y = 479-i;
168 		rect.w = 640;
169 		rect.h = 1;
170 		SDL_FillRect(surf, &rect, SDL_MapRGB(surf->format,8+i/2,32+i,8+i/2));
171 	}
172 
173 	/* Left vane box: */
174 	rect.x = 5; rect.y = 410;
175 	rect.w = 104; rect.h = 48+16;
176 	for (i = 1; i < 5; i++)
177 	{
178 		rectangleRGBA(surf, rect.x-i, rect.y-i,
179 			rect.x+rect.w-1+i, rect.y+rect.h-1+i,
180 			0xf0, 0xff, 0xf0, 0xff-i*0x3c);
181 	}
182 	SDL_FillRect(surf, &rect, white);
183 
184 	/* Right vane box: */
185 	rect.x = 5+(629-104); rect.y = 410;
186 	rect.w = 104; rect.h = 48+16;
187 	for (i = 1; i < 5; i++)
188 	{
189 		rectangleRGBA(surf, rect.x-i, rect.y-i,
190 			rect.x+rect.w-1+i, rect.y+rect.h-1+i,
191 			0xf0, 0xff, 0xf0, 0xff-i*0x3c);
192 	}
193 	SDL_FillRect(surf, &rect, white);
194 }
195 
scr_l_text(int x,int y,const char * text)196 void scr_l_text(int x, int y, const char *text)
197 {
198 	SDL_Rect rect;
199 
200 	// printf("v_gtext: %s\n", text);
201 
202 	y -= 12;
203 
204 	rect.x = x;
205 	rect.y = y;
206 	rect.w = strlen(text) * sdlgui_fontwidth;
207 	rect.h = sdlgui_fontheight;
208 	SDL_FillRect(surf, &rect, SDL_MapRGB(surf->format,0xff,0xff,0xff));
209 
210 	SDLGui_Text(x, y, text);
211 
212 	SDL_UpdateRects(surf, 1, &rect);
213 }
214 
215 /**
216  * Draw centered text
217  */
scr_ctr_text(int cx,int y,const char * text)218 void scr_ctr_text(int cx, int y, const char *text)
219 {
220 	SDL_Rect rect;
221 
222 	rect.w = strlen(text) * sdlgui_fontwidth;
223 	rect.h = sdlgui_fontheight;
224 	rect.x = cx - rect.w / 2;
225 	rect.y = y;
226 	SDL_FillRect(surf, &rect, SDL_MapRGB(surf->format,0xff,0xff,0xff));
227 
228 	SDLGui_Text(rect.x, rect.y, text);
229 
230 	SDL_UpdateRects(surf, 1, &rect);
231 }
232 
scr_circle(int x,int y,int w)233 void scr_circle(int x, int y, int w)
234 {
235 	SDL_Rect rect;
236 
237 	filledCircleColor(surf, x, y, w, the_color);
238 
239 	rect.x = max(x-w, 0);
240 	rect.y = max(y-w, 0);
241 	rect.w = min(2*w, 640-x+w);
242 	rect.h = min(2*w, 480-y+w);
243 	SDL_UpdateRects(surf, 1, &rect);
244 }
245 
update_fill_color(void)246 static void update_fill_color(void)
247 {
248 	if (fill_interior == 0)
249 	{
250 		fill_color = 0xffffffff;
251 	}
252 	else if (fill_interior == 1)
253 	{
254 		fill_color = 0x000000ff;
255 	}
256 	else if (fill_interior == 2)
257 	{
258 		switch (fill_style)
259 		{
260 		case 1:  fill_color = 0xc0b0a0ff; break;   // Table color
261 		case 2:  fill_color = 0x602060ff; break;   // King color
262 		case 9:  fill_color = 0x909080ff; break;   // Wall color
263 		case 11:  fill_color = 0xc04020ff; break;  // Roof color
264 		}
265 	}
266 	else
267 	{
268 		puts("unknown fill interior");
269 	}
270 }
271 
scr_sf_style(short val)272 void scr_sf_style(short val)
273 {
274 	fill_style = val;
275 	update_fill_color();
276 }
277 
scr_sf_interior(short val)278 void scr_sf_interior(short val)
279 {
280 	fill_interior = val;
281 	update_fill_color();
282 }
283 
scr_bar(short * xy)284 void scr_bar(short *xy)
285 {
286 	SDL_Rect rect;
287 	Uint8 r, g, b;
288 
289 	r = fill_color >> 24;
290 	g = fill_color >> 16;
291 	b = fill_color >> 8;
292 
293 	rect.x = xy[0];
294 	rect.y = xy[1];
295 	rect.w = xy[2]-xy[0]+1;
296 	rect.h = xy[3]-xy[1]+1;
297 	SDL_FillRect(surf, &rect, SDL_MapRGB(surf->format,r,g,b));
298 	rectangleColor(surf, xy[0], xy[1], xy[2], xy[3], the_color);
299 
300 	SDL_UpdateRects(surf, 1, &rect);
301 }
302 
303 
clr(short x,short y,short w,short h)304 void clr(short x, short y, short w, short h)
305 {
306 	SDL_Rect rect;
307 
308 	rect.x = x;
309 	rect.y = y;
310 	rect.w = w;
311 	rect.h = h;
312 	SDL_FillRect(surf, &rect, SDL_MapRGB(surf->format,0xff,0xff,0xff));
313 
314 	SDL_UpdateRect(surf, x,y, w,h);
315 }
316 
317 
clr_bg(short x,short y,short w,short h)318 void clr_bg(short x, short y, short w, short h)
319 {
320 	SDL_Rect rect;
321 
322 	rect.x = x;
323 	rect.y = y;
324 	rect.w = w;
325 	rect.h = h;
326 	SDL_FillRect(surf, &rect, bg_color);
327 
328 	SDL_UpdateRect(surf, x,y, w,h);
329 }
330 
331 
scr_fillarea(short num,short * xy)332 void scr_fillarea(short num, short *xy)
333 {
334 	int i;
335 	Sint16 vx[512], vy[512];
336 
337 	//printf("v_fillarea %i\n", num);
338 
339 	if (num > 512) {
340 		puts("v_fillarea overlow");
341 		exit(-2);
342 	}
343 
344 	for (i = 0; i < num; i++) {
345 		vx[i] = xy[i*2];
346 		vy[i] = xy[i*2+1];
347 	}
348 
349 	filledPolygonColor(surf, vx, vy, num, fill_color);
350 
351 	SDL_UpdateRect(surf, 0,0, 640,480);
352 }
353 
scr_pline(short num,short * xy)354 void scr_pline(short num, short *xy)
355 {
356 	int i;
357 	int maxx, maxy;
358 	int minx, miny;
359 
360 	minx = 639; miny = 399;
361 	maxx = 0; maxy = 0;
362 
363 	// printf("v_pline %i\n", num);
364 
365 	for (i = 0; i < num-1; i++)
366 	{
367 		if (xy[i*2] < 0 || xy[i*2] > 639
368 		    || xy[i*2+1] < 0 || xy[i*2+1] > 479) {
369 			printf("bad coordinates!\n");
370 			return;
371 		}
372 
373 		if (xy[i*2] > maxx)  maxx = xy[i*2];
374 		if (xy[i*2+1] > maxy)  maxy = xy[i*2+1];
375 		if (xy[i*2] < minx)  minx = xy[i*2];
376 		if (xy[i*2+1] < miny)  miny = xy[i*2+1];
377 		lineColor(surf, xy[i*2], xy[i*2+1], xy[i*2+2], xy[i*2+3], the_color|0x1000);
378 	}
379 
380 	if (xy[i*2] > maxx)  maxx = xy[i*2];
381 	if (xy[i*2+1] > maxy)  maxy = xy[i*2+1];
382 	if (xy[i*2] < minx)  minx = xy[i*2];
383 	if (xy[i*2+1] < miny)  miny = xy[i*2+1];
384 
385 	//printf("blit %i %i %i %i\n", minx,miny, maxx-minx+1,maxy-miny+1);
386 	SDL_UpdateRect(surf, minx,miny, maxx-minx+1,maxy-miny+1);
387 }
388 
389 
scr_line(int x1,int y1,int x2,int y2,int rgb)390 void scr_line(int x1, int y1, int x2, int y2, int rgb)
391 {
392 	lineColor(surf, x1, y1, x2, y2, (rgb<<8)|0xff);
393 }
394 
395 
scr_getpixel(int x,int y)396 int scr_getpixel(int x, int y)
397 {
398 	Uint32 *p = surf->pixels;
399 	Uint32 c;
400 	SDL_PixelFormat *fmt = surf->format;
401 
402 	c = p[y*640+x];
403 	c = ((((c & fmt->Rmask) >> fmt->Rshift) << fmt->Rloss) << 16)
404 	    | ((((c & fmt->Gmask) >> fmt->Gshift) << fmt->Gloss) << 8)
405 	    | (((c & fmt->Bmask) >> fmt->Bshift) << fmt->Bloss);
406 
407 	return c;
408 }
409 
scr_color(int c)410 void scr_color(int c)
411 {
412 	the_color = (c << 8) | 0xff;
413 }
414 
scr_fillcolor(int c)415 void scr_fillcolor(int c)
416 {
417 	fill_color = (c << 8) | 0xff;
418 }
419 
420 
421 /**
422  * Select foreground (1) or background (0) color
423  */
color(int c)424 void color(int c)
425 {
426 	if (c)
427 		the_color = 0x000000ff;
428 	else
429 		the_color = (bg_color<<8) | 0x0ff;
430 }
431 
432 
scr_init_done_button(int * bx,int * by,int * bw,int * bh)433 void scr_init_done_button(int *bx, int *by, int *bw, int *bh)
434 {
435 	int fontw, fonth;
436 
437 	/* Calculate the "Done" button coordinates */
438 	SDLGui_GetFontSize(&fontw, &fonth);
439 	*bx = donebuttondlg[0].x * fontw;
440 	*by = donebuttondlg[0].y * fonth;
441 	*bw = donebuttondlg[0].w * fontw;
442 	*bh = donebuttondlg[0].h * fonth;
443 
444 }
445 
scr_draw_done_button(int selected)446 void scr_draw_done_button(int selected)
447 {
448 	if (selected)
449 		donebuttondlg[1].state |= SG_SELECTED;
450 	else
451 		donebuttondlg[1].state &= ~SG_SELECTED;
452 
453 	SDLGui_DrawButton(donebuttondlg, 1);
454 
455 	SDL_UpdateRect(surf, 0,0, 0,0);
456 }
457 
458 
459 /**
460  * Draws a fast cannonball
461  */
scr_cannonball(int x,int y)462 void scr_cannonball(int x, int y)
463 {
464 	lineColor(surf, x-1,y-2, x+1,y-2, the_color);
465 	lineColor(surf, x-2,y-1, x+2,y-1, the_color);
466 	lineColor(surf, x-2,y  , x+2,y  , the_color);
467 	lineColor(surf, x-2,y+1, x+2,y+1, the_color);
468 	lineColor(surf, x-1,y+2, x+1,y+2, the_color);
469 }
470 
471 
472 /**
473  * Stores information about saved background area
474  */
475 struct savebg
476 {
477 	SDL_Rect rect;
478 	SDL_Rect bgrect;
479 	SDL_Surface *bgsurf;
480 };
481 
482 /**
483  * Save a part of the background of the screen
484  */
scr_save_bg(int x,int y,int w,int h)485 void *scr_save_bg(int x, int y, int w, int h)
486 {
487 	struct savebg *s;
488 
489 	s = malloc(sizeof(struct savebg));
490 	if (!s)
491 		return NULL;
492 
493 	s->rect.x = x; s->rect.y = y;
494 	s->rect.w = w; s->rect.h = h;
495 	s->bgrect.x = s->bgrect.y = 0;
496 	s->bgrect.w = s->rect.w;
497 	s->bgrect.h = s->rect.h;
498 	s->bgsurf = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, surf->format->BitsPerPixel,
499 	                              surf->format->Rmask, surf->format->Gmask,
500 	                              surf->format->Bmask, surf->format->Amask);
501 	if (s->bgsurf != NULL)
502 	{
503 		/* Save background */
504 		SDL_BlitSurface(surf, &s->rect, s->bgsurf, &s->bgrect);
505 	}
506 	else
507 	{
508 		fprintf(stderr, "scr_save_bg: CreateRGBSurface failed: %s\n",
509 		        SDL_GetError());
510 	}
511 
512 	return s;
513 }
514 
515 /**
516  * Restore part of the background
517  */
scr_restore_bg(void * ps)518 void scr_restore_bg(void *ps)
519 {
520 	struct savebg *s = ps;
521 
522 	/* Restore background */
523 	if (s != NULL && s->bgsurf != NULL)
524 	{
525 		SDL_BlitSurface(s->bgsurf, &s->bgrect, surf,  &s->rect);
526 		SDL_FreeSurface(s->bgsurf);
527 	}
528 
529 	SDL_UpdateRects(surf, 1, &s->rect);
530 
531 	free(ps);
532 }
533 
534 #if WITH_SDL2
SDL_UpdateRects(SDL_Surface * screen,int numrects,SDL_Rect * rects)535 void SDL_UpdateRects(SDL_Surface *screen, int numrects, SDL_Rect *rects)
536 {
537 #if USE_SDL2_RENDERER
538 	SDL_UpdateTexture(sdlTexture, NULL, screen->pixels, screen->pitch);
539 	SDL_RenderClear(sdlRenderer);
540 	SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL);
541 	SDL_RenderPresent(sdlRenderer);
542 #else
543 	SDL_BlitSurface(surf, rects, windowSurf, rects);
544 	SDL_UpdateWindowSurfaceRects(sdlWindow, rects, numrects);
545 #endif
546 }
547 
SDL_UpdateRect(SDL_Surface * screen,Sint32 x,Sint32 y,Sint32 w,Sint32 h)548 void SDL_UpdateRect(SDL_Surface *screen, Sint32 x, Sint32 y, Sint32 w, Sint32 h)
549 {
550 	SDL_Rect rect;
551 	if (w == 0 && h == 0) {
552 		w = 640;
553 		h = 480;
554 	}
555 	rect.x = x; rect.y = y;
556 	rect.w = w; rect.h = h;
557 	SDL_UpdateRects(screen, 1, &rect);
558 }
559 #endif
560 
scr_update(int x,int y,int w,int h)561 void scr_update(int x, int y, int w, int h)
562 {
563 	if (x >= 640 || y >= 480)
564 		return;
565 	if (x < 0)
566 		x = 0;
567 	if (y < 0)
568 		y = 0;
569 	if (x + w > 640)
570 		w = 640 - x;
571 	if (y + h > 480)
572 		h = 480 - y;
573 	SDL_UpdateRect(surf, x, y, w, h);
574 }
575