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