1 //
2 // nazghul - an old-school RPG engine
3 // Copyright (C) 2002, 2003 Gordon McNutt
4 //
5 // This program is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU General Public License as published by the Free
7 // Software Foundation; either version 2 of the License, or (at your option)
8 // any later version.
9 //
10 // This program is distributed in the hope that it will be useful, but WITHOUT
11 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 // more details.
14 //
15 // You should have received a copy of the GNU General Public License along with
16 // this program; if not, write to the Free Foundation, Inc., 59 Temple Place,
17 // Suite 330, Boston, MA 02111-1307 USA
18 //
19 // Gordon McNutt
20 // gmcnutt@users.sourceforge.net
21 //
22 #include "screen.h"
23 #include "common.h"
24 #include "ascii.h"
25 #include "sprite.h"
26 #include "status.h"
27 #include "foogod.h"
28 #include "cfg.h"
29 #include "images.h"
30 #include "nazghul.h" // for FullScreenMode
31
32 #include <png.h>
33 #include <unistd.h>
34 #include <stdarg.h>
35 #include <assert.h>
36
37 #include <SDL_image.h>
38
39 #define N_SHADERS 3
40 #define MAX_SHADER (N_SHADERS - 1)
41 #define SHADER_W STAT_W
42 #define SHADER_H STAT_H_MAX
43 #define HIGHLIGHT_THICKNESS 2
44
45 /* Frame image indices */
46 #define FRAME_ULC 0
47 #define FRAME_TD 1
48 #define FRAME_URC 2
49 #define FRAME_ENDT 3
50 #define FRAME_TR 4
51 #define FRAME_TX 5
52 #define FRAME_TL 6
53 #define FRAME_VERT 7
54 #define FRAME_LLC 8
55 #define FRAME_TU 9
56 #define FRAME_LRC 10
57 #define FRAME_ENDD 11
58 #define FRAME_ENDL 12
59 #define FRAME_HORZ 13
60 #define FRAME_ENDR 14
61 #define FRAME_DOT 15
62 #define FRAME_NUM_SPRITES 16
63
64 /* Enable this to dump surfaces and video info */
65 #ifndef SCREEN_DEBUG
66 #define SCREEN_DEBUG 0
67 #endif
68
69 static SDL_Surface *Screen;
70 static SDL_Surface *Shaders[N_SHADERS];
71 static SDL_Surface *Highlight;
72 static struct sprite *FrameSprites[FRAME_NUM_SPRITES];
73 static int Zoom;
74 static char screen_buf[128];
75
76 Uint32 Black;
77 Uint32 Blue;
78 Uint32 White;
79 Uint32 Green;
80 Uint32 Red;
81 Uint32 Yellow;
82 Uint32 Cyan;
83 Uint32 Magenta;
84 Uint32 Gray;
85
86 Uint32 TextRed;
87 Uint32 TextGreen;
88 Uint32 TextBlue;
89 Uint32 TextYellow;
90 Uint32 TextCyan;
91 Uint32 TextMagenta;
92
93
94 SDL_Color fontWhite = { 0xff, 0xff, 0xff, 0x00 };
95 SDL_Color fontBlack = { 0, 0, 0, 0 };
96
97 static void scaled_blit(SDL_Surface * source, SDL_Rect * from,
98 SDL_Surface * dest, SDL_Rect * to);
99
screenInitColors(void)100 void screenInitColors(void)
101 {
102
103 Black = SDL_MapRGB(Screen->format, 0x00, 0x00, 0x00);
104 White = SDL_MapRGB(Screen->format, 0xff, 0xff, 0xff);
105 Red = SDL_MapRGB(Screen->format, 0xff, 0x00, 0x00);
106 TextRed = SDL_MapRGB(Screen->format, 0xff, 0x99, 0x99);
107 Green = SDL_MapRGB(Screen->format, 0x00, 0xff, 0x00);
108 TextGreen = SDL_MapRGB(Screen->format, 0x99, 0xff, 0x99);
109 Blue = SDL_MapRGB(Screen->format, 0x00, 0x00, 0xff);
110 TextBlue = SDL_MapRGB(Screen->format, 0x99, 0x99, 0xff);
111 Yellow = SDL_MapRGB(Screen->format, 0xff, 0xff, 0x00);
112 TextYellow = SDL_MapRGB(Screen->format, 0xff, 0xff, 0x99);
113 Cyan = SDL_MapRGB(Screen->format, 0x00, 0xff, 0xff);
114 TextCyan = SDL_MapRGB(Screen->format, 0x99, 0xff, 0xff);
115 Magenta = SDL_MapRGB(Screen->format, 0xff, 0xff, 0x00);
116 TextMagenta = SDL_MapRGB(Screen->format, 0xff, 0x99, 0xff);
117 Gray = SDL_MapRGB(Screen->format, 0x80, 0x80, 0x80);
118 }
119
dump_SDL_PixelFormat(SDL_PixelFormat * fmt)120 void dump_SDL_PixelFormat(SDL_PixelFormat *fmt)
121 {
122 printf("Pixel Format:\n");
123 printf(" palette: %p\n", fmt->palette);
124 printf("BitsPerPixel: %d\n", fmt->BitsPerPixel);
125 printf(" Rmask: 0x%x\n", fmt->Rmask);
126 printf(" Gmask: 0x%x\n", fmt->Gmask);
127 printf(" Bmask: 0x%x\n", fmt->Bmask);
128 printf(" Amask: 0x%x\n", fmt->Amask);
129 printf(" Rshift: %d\n", fmt->Rshift);
130 printf(" Gshift: %d\n", fmt->Gshift);
131 printf(" Bshift: %d\n", fmt->Bshift);
132 printf(" Ashift: %d\n", fmt->Ashift);
133 printf(" Rloss: %d\n", fmt->Rloss);
134 printf(" Gloss: %d\n", fmt->Gloss);
135 printf(" Bloss: %d\n", fmt->Bloss);
136 printf(" Aloss: %d\n", fmt->Aloss);
137 printf(" colorkey: 0x%x\n", fmt->colorkey);
138 printf(" alpha: 0x%x\n", fmt->alpha);
139 }
140
dump_SDL_VideoInfo(const SDL_VideoInfo * fmt)141 void dump_SDL_VideoInfo(const SDL_VideoInfo *fmt)
142 {
143 printf("Video Info:\n");
144 printf(" hw_available: %c\n", fmt->hw_available ? 'y' : 'n');
145 printf(" wm_available: %c\n", fmt->wm_available ? 'y' : 'n');
146 printf(" blit_hw: %c\n", fmt->blit_hw ? 'y' : 'n');
147 printf(" blit_hw_CC: %c\n", fmt->blit_hw_CC ? 'y' : 'n');
148 printf(" blit_hw_A: %c\n", fmt->blit_hw_A ? 'y' : 'n');
149 printf(" blit_sw: %c\n", fmt->blit_sw ? 'y' : 'n');
150 printf(" blit_sw_CC: %c\n", fmt->blit_sw_CC ? 'y' : 'n');
151 printf(" blit_sw_A: %c\n", fmt->blit_sw_A ? 'y' : 'n');
152 printf(" blit_fill: %c\n", fmt->blit_fill ? 'y' : 'n');
153 printf(" video_mem: %d\n", fmt->video_mem);
154 dump_SDL_PixelFormat(fmt->vfmt);
155 }
156
dump_SDL_Surface(SDL_Surface * surf)157 void dump_SDL_Surface(SDL_Surface *surf)
158 {
159 printf("Surface Info:\n");
160 printf(" flags:\n");
161 if (surf->flags & SDL_SWSURFACE)
162 printf(" SDL_SWSURFACE\n");
163 if (surf->flags & SDL_HWSURFACE)
164 printf(" SDL_HWSURFACE\n");
165 if (surf->flags & SDL_ASYNCBLIT)
166 printf(" SDL_ASYNCBLIT\n");
167 if (surf->flags & SDL_ANYFORMAT)
168 printf(" SDL_ANYFORMAT\n");
169 if (surf->flags & SDL_HWPALETTE)
170 printf(" SDL_HWPALETTE\n");
171 if (surf->flags & SDL_DOUBLEBUF)
172 printf(" SDL_DOUBLEBUF\n");
173 if (surf->flags & SDL_FULLSCREEN)
174 printf(" SDL_FULLSCREEN\n");
175 if (surf->flags & SDL_OPENGL)
176 printf(" SDL_OPENGL\n");
177 if (surf->flags & SDL_OPENGLBLIT)
178 printf(" SDL_OPENGLBLIT\n");
179 if (surf->flags & SDL_RESIZABLE)
180 printf(" SDL_RESIZABLE\n");
181 if (surf->flags & SDL_HWACCEL)
182 printf(" SDL_HWACCEL\n");
183 if (surf->flags & SDL_SRCCOLORKEY)
184 printf(" SDL_SRCCOLORKEY\n");
185 if (surf->flags & SDL_RLEACCEL)
186 printf(" SDL_RLEACCEL\n");
187 if (surf->flags & SDL_SRCALPHA)
188 printf(" SDL_SRCALPHA\n");
189 if (surf->flags & SDL_PREALLOC)
190 printf(" SDL_PREALLOC\n");
191 printf(" w: %d\n", surf->w);
192 printf(" h: %d\n", surf->h);
193 printf(" pitch: %d\n", surf->pitch);
194 printf(" pixels: %p\n", surf->pixels);
195 printf(" clip_rect: [%d %d %d %d]\n",
196 surf->clip_rect.x,
197 surf->clip_rect.y,
198 surf->clip_rect.w,
199 surf->clip_rect.h);
200 printf(" refcount: %d\n", surf->refcount);
201 dump_SDL_PixelFormat(surf->format);
202
203 }
204
screenInitScreen(void)205 void screenInitScreen(void)
206 {
207 Uint32 flags = SDL_ANYFORMAT;
208 const SDL_VideoInfo *fmt;
209
210 const int SCREEN_BPP = 0; /* use display BPP */
211
212 if (SDL_Init(SDL_INIT_VIDEO) < 0) {
213 perror_sdl("SDL_Init");
214 exit(-1);
215 }
216 atexit(SDL_Quit);
217
218 fmt = SDL_GetVideoInfo();
219 if (!fmt) {
220 perror_sdl("SDL_GetVideoInfo");
221 exit(-1);
222 }
223
224 if (SCREEN_DEBUG) {
225 dump_SDL_VideoInfo(fmt);
226 }
227
228 if (fmt->blit_hw_CC && fmt->blit_fill) {
229 flags |= SDL_HWSURFACE;
230 flags |= SDL_DOUBLEBUF;
231 }
232 if (FullScreenMode) {
233 flags |= SDL_FULLSCREEN;
234 }
235
236 Screen = SDL_SetVideoMode(SCREEN_W, SCREEN_H, SCREEN_BPP, flags);
237 if (!Screen) {
238 perror_sdl("SDL_SetVideoMode");
239 exit(-1);
240 }
241
242 if (SCREEN_DEBUG) {
243 printf("Video initialized to...\n");
244 dump_SDL_Surface(Screen);
245 }
246
247 SDL_WM_SetCaption(APPLICATION_NAME, APPLICATION_NAME);
248 }
249
screen_fade_surface(SDL_Surface * surf,int fade_level)250 void screen_fade_surface(SDL_Surface * surf, int fade_level)
251 {
252 int x, y;
253 Uint8 *pix;
254 Uint8 trans;
255 int base;
256 int toggle;
257
258 assert(surf->format->BitsPerPixel == 8);
259
260 if (fade_level == 0)
261 return;
262
263 pix = (Uint8 *) surf->pixels;
264 trans = (Uint8) surf->format->colorkey;
265
266 for (y = 0; y < surf->h; y++) {
267 base = y * surf->pitch;
268 toggle = y % 2;
269 for (x = 0; x < surf->w; x++) {
270 int i = base + x;
271 if (toggle) {
272 if (pix[i] != trans) {
273 toggle = 0;
274 pix[i] = trans;
275 }
276 } else if (pix[i] != trans) {
277 toggle = 1;
278 }
279 } // for (x)
280 } // for (y)
281
282 assert(surf->format->BitsPerPixel == 8);
283
284 screen_fade_surface(surf, fade_level - 1);
285 }
286
create_shader(int fade_level)287 static SDL_Surface *create_shader(int fade_level)
288 {
289 SDL_Surface *shader;
290
291 shader = screenCreateSurface(SHADER_W, SHADER_H);
292 if (shader == NULL)
293 return NULL;
294
295 SDL_FillRect(shader, NULL, SDL_MapRGBA(shader->format, 0, 0, 0, 0));
296
297 if (shader->format->palette != NULL) {
298 SDL_LockSurface(shader);
299 screen_fade_surface(shader, fade_level);
300 SDL_UnlockSurface(shader);
301 }
302
303 return shader;
304 }
305
screenInitShader(void)306 void screenInitShader(void)
307 {
308 int n, i;
309
310 n = (Screen->format->BitsPerPixel == 8) ? N_SHADERS : 1;
311
312 for (i = 0; i < n; i++) {
313 Shaders[i] = create_shader(i);
314 }
315 }
316
screenInitHighlight(void)317 void screenInitHighlight(void)
318 {
319 Highlight = screenCreateSurface(SHADER_W, SHADER_H);
320 assert(Highlight != NULL);
321
322 SDL_FillRect(Highlight, NULL, SDL_MapRGBA(Highlight->format, 255, 255, 255, 0));
323
324 if (Highlight->format->palette != NULL) {
325 SDL_LockSurface(Highlight);
326 screen_fade_surface(Highlight, 4);
327 SDL_UnlockSurface(Highlight);
328 }
329 }
330
screenInitFrame(void)331 static void screenInitFrame(void)
332 {
333 int i;
334 char *fname = cfg_get("frame-image-filename");
335 struct images *ss_frame = 0;
336
337 if (!fname) {
338 warn("No frame image filename!");
339 return;
340 }
341
342 memset(FrameSprites, 0, sizeof(FrameSprites));
343
344 ss_frame = images_new(0, 16, 16, 4, 4, 0, 0, fname);
345 assert(ss_frame);
346
347 for (i = 0; i < FRAME_NUM_SPRITES; i++) {
348 FrameSprites[i] = sprite_new(0, 1, i, 0, 0, ss_frame);
349 assert(FrameSprites[i]);
350 }
351 }
352
screenInit(void)353 int screenInit(void)
354 {
355 screenInitScreen();
356 screenInitColors();
357 screenInitShader();
358 screenInitHighlight();
359 screenInitFrame();
360 Zoom = 1;
361
362 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY,
363 SDL_DEFAULT_REPEAT_INTERVAL);
364
365 return 0;
366 }
367
screenErase(SDL_Rect * rect)368 void screenErase(SDL_Rect * rect)
369 {
370 SDL_FillRect(Screen, rect, Black);
371 }
372
screenFill(SDL_Rect * rect,Uint32 color)373 void screenFill(SDL_Rect * rect, Uint32 color)
374 {
375 SDL_Rect tmp = *rect;
376 rect->w /= Zoom;
377 rect->h /= Zoom;
378 SDL_FillRect(Screen, rect, color);
379 }
380
screenUpdate(SDL_Rect * rect)381 void screenUpdate(SDL_Rect * rect)
382 {
383 if (rect) {
384 SDL_UpdateRect(Screen, rect->x, rect->y, rect->w, rect->h);
385 } else {
386 SDL_Flip(Screen);
387 }
388 }
389
390 /* bpp-independent macro to test if a pixel is magenta */
391 #define isTransparent(ff,pp) \
392 (((ff)->Rmask&(pp))==(ff)->Rmask \
393 && ((ff)->Gmask&(pp))==0 \
394 && ((ff)->Bmask&(pp))==(ff)->Bmask)
395
scaled_blit_32bpp(SDL_Surface * source,SDL_Rect * from,SDL_Surface * dest,SDL_Rect * to,int spitch,int dpitch)396 static void scaled_blit_32bpp(SDL_Surface * source, SDL_Rect * from,
397 SDL_Surface * dest, SDL_Rect * to,
398 int spitch, int dpitch)
399 {
400 int dx, dy, di, sx, sy, si;
401 Uint32 *d, *s;
402
403 d = (Uint32 *) dest->pixels;
404 s = (Uint32 *) source->pixels;
405
406 for (dy = 0; dy < to->h; dy++) {
407 sy = dy * Zoom;
408 for (dx = 0; dx < to->w; dx++) {
409 sx = dx * Zoom;
410 di = (dy + to->y) * dpitch + (dx + to->x);
411 si = (sy + from->y) * spitch + (sx + from->x);
412 if (!isTransparent(dest->format, s[si]))
413 d[di] = s[si];
414 } // for (dx)
415 } // for (dy)
416 }
417
scaled_blit_16bpp(SDL_Surface * source,SDL_Rect * from,SDL_Surface * dest,SDL_Rect * to,int spitch,int dpitch)418 static void scaled_blit_16bpp(SDL_Surface * source, SDL_Rect * from,
419 SDL_Surface * dest, SDL_Rect * to,
420 int spitch, int dpitch)
421 {
422 int dx, dy, di, sx, sy, si;
423 Uint16 *d, *s;
424
425 d = (Uint16 *) dest->pixels;
426 s = (Uint16 *) source->pixels;
427
428 for (dy = 0; dy < to->h; dy++) {
429 sy = dy * Zoom;
430 for (dx = 0; dx < to->w; dx++) {
431 sx = dx * Zoom;
432 di = (dy + to->y) * dpitch + (dx + to->x);
433 si = (sy + from->y) * spitch + (sx + from->x);
434 if (! isTransparent(dest->format, s[si]))
435 d[di] = s[si];
436 } // for (dx)
437 } // for (dy)
438 }
439
scaled_blit_8bpp(SDL_Surface * source,SDL_Rect * from,SDL_Surface * dest,SDL_Rect * to,int spitch,int dpitch)440 static void scaled_blit_8bpp(SDL_Surface * source, SDL_Rect * from,
441 SDL_Surface * dest, SDL_Rect * to,
442 int spitch, int dpitch)
443 {
444 int dx, dy, di, sx, sy, si;
445 Uint8 *d, *s;
446
447 d = (Uint8 *) dest->pixels;
448 s = (Uint8 *) source->pixels;
449
450 for (dy = 0; dy < to->h; dy++) {
451 sy = dy * Zoom;
452 for (dx = 0; dx < to->w; dx++) {
453 sx = dx * Zoom;
454 di = (dy + to->y) * dpitch + (dx + to->x);
455 si = (sy + from->y) * spitch + (sx + from->x);
456 d[di] = s[si];
457 } // for (dx)
458 } // for (dy)
459 }
460
461 /* scale_then_blit_normal -- cheesy hack to support scaled blitting of
462 * incompatible surface types. This blits the source to a temporary compatible
463 * surface using the scaled_blit function, then blits the tmp surface to the
464 * screen with Zoom=1. Inefficient but functional. */
scale_then_blit_normal(SDL_Surface * source,SDL_Rect * from,SDL_Surface * dest,SDL_Rect * to)465 static void scale_then_blit_normal(SDL_Surface * source, SDL_Rect * from,
466 SDL_Surface * dest, SDL_Rect * to)
467 {
468 SDL_Surface *tmp = 0;
469 SDL_Rect rect;
470 int o_zoom = Zoom;
471
472 /* Create a temporary surface for the scaled blit which has the same
473 * format as the source. */
474 tmp = SDL_CreateRGBSurface(source->flags,
475 from->w / Zoom, from->h / Zoom,
476 source->format->BitsPerPixel,
477 source->format->Rmask,
478 source->format->Gmask,
479 source->format->Bmask,
480 source->format->Amask);
481 if (!tmp) {
482 perror_sdl("SDL_CreateRGBSurface");
483 return;
484 }
485
486 /* Setup a rect for the tmp surface. */
487 rect.x = 0;
488 rect.y = 0;
489 rect.w = to->w;
490 rect.h = to->h;
491
492 /* Do a scaled_blit from the source to the temporary surface. */
493 scaled_blit(source, from, tmp, &rect);
494
495 /* Do a normal blit from the tmp surface to the final dest, temporarily
496 * setting Zoom factor to 1 to prevent another call into
497 * scaled_blit(). */
498 o_zoom = Zoom;
499 Zoom = 1;
500 screenBlit(tmp, &rect, to);
501 Zoom = o_zoom;
502
503 /* Free the tmp surface. */
504 SDL_FreeSurface(tmp);
505 }
506
scaled_blit(SDL_Surface * source,SDL_Rect * from,SDL_Surface * dest,SDL_Rect * to)507 static void scaled_blit(SDL_Surface * source, SDL_Rect * from,
508 SDL_Surface * dest, SDL_Rect * to)
509 {
510 int dpitch, spitch;
511
512 assert(Zoom > 0);
513
514 /* This is not a general-purpose blitting routine. If the source and
515 * destination surfaces don't have the same format then use a hack to
516 * workaround it. */
517 if (source->format->BitsPerPixel != dest->format->BitsPerPixel
518 || source->format->Amask != dest->format->Amask
519 ) {
520 scale_then_blit_normal(source, from, dest, to);
521 return;
522 }
523
524 to->w /= Zoom;
525 to->h /= Zoom;
526
527 dpitch = dest->pitch / dest->format->BytesPerPixel;
528 spitch = source->pitch / source->format->BytesPerPixel;
529
530 if (SDL_LockSurface(dest) < 0)
531 return;
532
533 switch (dest->format->BitsPerPixel) {
534 case 32:
535 scaled_blit_32bpp(source, from, dest, to, spitch, dpitch);
536 break;
537 case 16:
538 scaled_blit_16bpp(source, from, dest, to, spitch, dpitch);
539 break;
540 case 8:
541 scaled_blit_8bpp(source, from, dest, to, spitch, dpitch);
542 break;
543 default:
544 assert(0);
545 break;
546 }
547
548 SDL_UnlockSurface(dest);
549 }
550
screenBlit(SDL_Surface * source,SDL_Rect * from,SDL_Rect * to)551 void screenBlit(SDL_Surface * source, SDL_Rect * from, SDL_Rect * to)
552 {
553 /* Clipping is really only needed for wave sprites right now. If the
554 * following proves to be too expensive on slow machines... */
555 if (to) {
556 SDL_Rect _to = *to;
557 SDL_SetClipRect(Screen, &_to);
558 if (Zoom > 1) {
559
560 // Clients are allowed to pass a NULL from rect,
561 // indicating they want to blit the whole source
562 // area. But the scaled blits require a non-NULL
563 // from rect.
564 SDL_Rect _from;
565 if (from == NULL) {
566 _from.x = 0;
567 _from.y = 0;
568 _from.w = source->w;
569 _from.h = source->h;
570 from = &_from;
571 }
572
573 scaled_blit(source, from, Screen, &_to);
574 } else {
575 if (SDL_BlitSurface(source, from, Screen, &_to) < 0)
576 perror_sdl("SDL_BlitSurface");
577 }
578 SDL_SetClipRect(Screen, 0);
579 } else {
580 SDL_SetClipRect(Screen, to);
581 if (SDL_BlitSurface(source, from, Screen, NULL) < 0)
582 perror_sdl("SDL_BlitSurface");
583 SDL_SetClipRect(Screen, 0);
584 }
585 }
586
screenWidth(void)587 int screenWidth(void)
588 {
589 return Screen->w;
590 }
591
screenHeight(void)592 int screenHeight(void)
593 {
594 return Screen->h;
595 }
596
screenFormat(void)597 SDL_PixelFormat *screenFormat(void)
598 {
599 return Screen->format;
600 }
601
screenFlash(SDL_Rect * rect,int mdelay,Uint32 color)602 void screenFlash(SDL_Rect * rect, int mdelay, Uint32 color)
603 {
604 screenFill(rect, color);
605 screenUpdate(rect);
606 //usleep(mdelay * 1000);
607 SDL_Delay(mdelay);
608 }
609
screenPrint(SDL_Rect * rect,int flags,const char * fmt,...)610 void screenPrint(SDL_Rect * rect, int flags, const char *fmt, ...)
611 {
612 va_list args;
613 int i;
614 int x = rect->x;
615 int y = rect->y;
616 int alen, slen, stop;
617
618 /* Print the string to a buffer. */
619 va_start(args, fmt);
620 vsnprintf(screen_buf, sizeof(screen_buf), fmt, args);
621 va_end(args);
622
623 slen = strlen(screen_buf);
624 alen = asciiStrlen(screen_buf);
625 stop = rect->x + (rect->w * ASCII_W);
626
627 /* If painting on the border then first fill the line with the border
628 * image. */
629 if (flags & SP_ONBORDER) {
630 for (x = rect->x; x < rect->x + rect->w; x += BORDER_W)
631 sprite_paint(FrameSprites[FRAME_HORZ], 0, x, rect->y);
632 }
633
634 /* Calculate offset for center and right-justified cases */
635 if (flags & SP_CENTERED) {
636 int w = alen * ASCII_W;
637 if (w > rect->w) {
638 w = rect->w;
639 }
640 x = (rect->w - w) / 2 + rect->x;
641 } else if (flags & SP_RIGHTJUSTIFIED) {
642 int w = alen * ASCII_W;
643 if (w > rect->w) {
644 w = rect->w;
645 }
646 x = (rect->w - w) + rect->x;
647 }
648
649 /* If painting on the border, then paint the right stub
650 * to the left of the text. */
651 if (flags & SP_ONBORDER) {
652 sprite_paint(FrameSprites[FRAME_ENDR], 0, x - BORDER_W, rect->y);
653 }
654
655 /* Paint the characters until we run out or hit the end of the
656 * region. */
657 for (i = 0; i < slen && x < stop; i++) {
658
659 if (asciiPaint(screen_buf[i], x, y, Screen)) {
660
661 /* Move right. */
662 x += ASCII_W;
663 }
664 }
665
666 /* If painting on the border, then paint the left stub
667 * to the right of the text. */
668 if (flags & SP_ONBORDER) {
669 sprite_paint(FrameSprites[FRAME_ENDL], 0, x, rect->y);
670 }
671 }
672
screen_repaint_frame(void)673 void screen_repaint_frame(void)
674 {
675 int i;
676
677 // First draw the top and bottom horizontal bars. Leave gaps for the
678 // sky and wind windows. Originally I went ahead and painted over them
679 // here, relying on their update routines to black out their
680 // backgrounds. But when I started using the tall/short mode for the
681 // status window I found that this was no longer good enough. The
682 // backgrounds of these windows tended to flash when switching mode.
683
684 // Draw the top bar from the top left corner to the sky window.
685 for (i = 0; i < SKY_X - BORDER_W; i += BORDER_W)
686 sprite_paint(FrameSprites[FRAME_HORZ], 0, i, 0);
687
688 // Draw the top bar from the sky window to the left edge of the status
689 // window's title.
690 for (i = SKY_X + SKY_W + BORDER_W; i < STAT_X; i += BORDER_W)
691 sprite_paint(FrameSprites[FRAME_HORZ], 0, i, 0);
692
693 // Draw the bottom of the map from the left edge to the wind window.
694 for (i = 0; i < (int) (WIND_X - BORDER_W); i += BORDER_W)
695 sprite_paint(FrameSprites[FRAME_HORZ], 0, i, MAP_X + MAP_H);
696
697 // Draw the bottom of the map from the wind window to the left edge of
698 // the console window.
699 for (i = WIND_X + WIND_W + BORDER_W; i < CONS_X - BORDER_W;
700 i += BORDER_W)
701 sprite_paint(FrameSprites[FRAME_HORZ], 0, i, MAP_X + MAP_H);
702
703 // Draw the bar across the bottom of the screen.
704 for (i = 0; i < SCREEN_W; i += BORDER_W)
705 sprite_paint(FrameSprites[FRAME_HORZ], 0, i, SCREEN_H - BORDER_H);
706
707 // Next draw the bottom of the status and food/gold window.
708 for (i = (MAP_X + MAP_W); i < SCREEN_W; i += BORDER_W) {
709 sprite_paint(FrameSprites[FRAME_HORZ], 0, i, STAT_Y + status_get_h());
710 sprite_paint(FrameSprites[FRAME_HORZ], 0, i,
711 foogod_get_y() + FOOGOD_H);
712 }
713
714 // Next rough in all the vertical lines.
715 for (i = 0; i < SCREEN_H; i += BORDER_H) {
716 sprite_paint(FrameSprites[FRAME_VERT], 0, 0, i);
717 sprite_paint(FrameSprites[FRAME_VERT], 0, MAP_X + MAP_W, i);
718 sprite_paint(FrameSprites[FRAME_VERT], 0, SCREEN_W - BORDER_W, i);
719 }
720
721 // Now paint the four corner pieces
722 sprite_paint(FrameSprites[FRAME_ULC], 0, 0, 0);
723 sprite_paint(FrameSprites[FRAME_URC], 0, SCREEN_W - BORDER_W, 0);
724 sprite_paint(FrameSprites[FRAME_LLC], 0, 0, SCREEN_H - BORDER_H);
725 sprite_paint(FrameSprites[FRAME_LRC], 0, SCREEN_W - BORDER_W,
726 SCREEN_H - BORDER_H);
727
728 // Then all the right-facing tee-joints
729 sprite_paint(FrameSprites[FRAME_TR], 0, 0, MAP_Y + MAP_H);
730 sprite_paint(FrameSprites[FRAME_TR], 0, MAP_X + MAP_W,
731 STAT_Y + status_get_h());
732 sprite_paint(FrameSprites[FRAME_TR], 0, MAP_X + MAP_W,
733 foogod_get_y() + FOOGOD_H);
734
735 // Then all the left-facing tee-joints
736 sprite_paint(FrameSprites[FRAME_TL], 0, MAP_X + MAP_W, MAP_Y + MAP_H);
737 sprite_paint(FrameSprites[FRAME_TL], 0, SCREEN_W - BORDER_W,
738 STAT_Y + status_get_h());
739 sprite_paint(FrameSprites[FRAME_TL], 0, SCREEN_W - BORDER_W,
740 foogod_get_y() + FOOGOD_H);
741
742 // Then the downward and upward-facing tee-joints
743 sprite_paint(FrameSprites[FRAME_TD], 0, MAP_X + MAP_W, 0);
744 sprite_paint(FrameSprites[FRAME_TU], 0, MAP_X + MAP_W, SCREEN_H - BORDER_H);
745
746 // And then the stubs around the sky section
747 sprite_paint(FrameSprites[FRAME_ENDR], 0, SKY_X - BORDER_W, 0);
748 sprite_paint(FrameSprites[FRAME_ENDL], 0, SKY_X + SKY_W, 0);
749
750 // And finally stubs around the wind section
751 sprite_paint(FrameSprites[FRAME_ENDR], 0, WIND_X - BORDER_W, MAP_X + MAP_H);
752 sprite_paint(FrameSprites[FRAME_ENDL], 0, WIND_X + WIND_W, MAP_X + MAP_H);
753
754 // And some stubs around the status title section
755 sprite_paint(FrameSprites[FRAME_ENDR], 0, STAT_X, 0);
756 sprite_paint(FrameSprites[FRAME_ENDL], 0, STAT_X + STAT_W - BORDER_W, 0);
757
758 screenUpdate(0);
759
760 }
761
screenCreateSurface(int w,int h)762 SDL_Surface *screenCreateSurface(int w, int h)
763 {
764 SDL_Surface *surf = NULL, *tmp;
765
766 tmp = SDL_CreateRGBSurface(Screen->flags,
767 w, h,
768 Screen->format->BitsPerPixel,
769 Screen->format->Rmask,
770 Screen->format->Gmask,
771 Screen->format->Bmask,
772 Screen->format->Amask);
773
774 // surf->format->palette = Screen->format->palette;
775
776 if (tmp == NULL) {
777 perror_sdl("SDL_CreateRGBSurface");
778 return NULL;
779 }
780
781 surf = SDL_DisplayFormat(tmp);
782 SDL_FreeSurface(tmp);
783
784 if (surf == NULL) {
785 perror_sdl("SDL_DisplayFormat");
786 return NULL;
787 }
788
789 if (surf->format->palette) {
790 SDL_SetColorKey(surf, SDL_SRCCOLORKEY,
791 SDL_MapRGB(surf->format, 0xFF, 0x00, 0xFF));
792 }
793
794 return surf;
795 }
796
screenCopy(SDL_Rect * from,SDL_Rect * to,SDL_Surface * dest)797 void screenCopy(SDL_Rect * from, SDL_Rect * to, SDL_Surface * dest)
798 {
799 if (SDL_BlitSurface(Screen, from, dest, to) < 0)
800 perror_sdl("SDL_BlitSurface");
801
802 assert(from);
803 assert(dest);
804
805 SDL_Rect _from = *from;
806
807 if (Zoom > 1) {
808 // Clients are allowed to pass a NULL 'to' rect,
809 // indicating they want to blit the whole dest
810 // area. But the scaled blits require a non-NULL
811 // 'to' rect.
812 SDL_Rect _to;
813 if (to == NULL) {
814 _to.x = 0;
815 _to.y = 0;
816 _to.w = dest->w;
817 _to.h = dest->h;
818 to = &_to;
819 }
820 scaled_blit(Screen, &_from, dest, to);
821 } else {
822 if (SDL_BlitSurface(Screen, &_from, dest, to) < 0)
823 perror_sdl("SDL_BlitSurface");
824 }
825 }
826
screenShade(SDL_Rect * area,unsigned char amount)827 void screenShade(SDL_Rect * area, unsigned char amount)
828 {
829 SDL_Surface *shade;
830
831 assert(area->w <= SHADER_W);
832 assert(area->h <= SHADER_H);
833
834 if (amount == 0)
835 return;
836
837 if (Screen->format->BitsPerPixel == 8) {
838 shade = Shaders[MAX_SHADER - (amount * MAX_SHADER) / 255];
839 } else {
840 shade = Shaders[0];
841 SDL_SetAlpha(shade, SDL_SRCALPHA, amount);
842 }
843 screenBlit(shade, NULL, area);
844 }
845
screenHighlightColored(SDL_Rect * area,Uint32 color)846 void screenHighlightColored(SDL_Rect * area, Uint32 color)
847 {
848 SDL_Rect edge;
849
850 // ---------------------------------------------------------------------
851 // Top edge
852 // ---------------------------------------------------------------------
853
854 edge.x = area->x;
855 edge.y = area->y;
856 edge.w = area->w;
857 edge.h = HIGHLIGHT_THICKNESS;
858
859 screenFill(&edge, color);
860
861 // ---------------------------------------------------------------------
862 // Bottom edge
863 // ---------------------------------------------------------------------
864
865 edge.x = area->x;
866 edge.y = area->y + (area->h/Zoom) - HIGHLIGHT_THICKNESS;
867 edge.w = area->w;
868 edge.h = HIGHLIGHT_THICKNESS;
869
870 screenFill(&edge, color);
871
872 // ---------------------------------------------------------------------
873 // Left edge
874 // ---------------------------------------------------------------------
875
876 edge.x = area->x;
877 edge.y = area->y;
878 edge.w = HIGHLIGHT_THICKNESS;
879 edge.h = area->h;
880
881 screenFill(&edge, color);
882
883 // ---------------------------------------------------------------------
884 // Right edge
885 // ---------------------------------------------------------------------
886
887 edge.x = area->x + (area->w/Zoom) - HIGHLIGHT_THICKNESS;
888 edge.y = area->y;
889 edge.w = HIGHLIGHT_THICKNESS;
890 edge.h = area->h;
891
892 screenFill(&edge, color);
893 }
894
screenHighlight(SDL_Rect * area)895 void screenHighlight(SDL_Rect *area)
896 {
897 screenHighlightColored(area, White);
898 }
899
screenLock(void)900 int screenLock(void)
901 {
902 return SDL_LockSurface(Screen);
903 }
904
screenUnlock(void)905 void screenUnlock(void)
906 {
907 SDL_UnlockSurface(Screen);
908 }
909
910 /* assumes the pixel value is gotten from screenMapRGB() i.e. safe! */
screenSetPixel(int x,int y,Uint32 color)911 void screenSetPixel(int x, int y, Uint32 color)
912 {
913 Uint8 *pix = (Uint8*)(Screen->pixels);
914 pix += y * Screen->pitch + x * Screen->format->BytesPerPixel;
915
916 switch (Screen->format->BytesPerPixel) {
917 case 4: *(Uint32*)pix = (Uint32)color; break;
918 case 2: *(Uint16*)pix = (Uint16)color; break;
919 case 1: *(Uint8 *)pix = (Uint8)color; break;
920 default: assert(0); break;
921 }
922 }
923
screenMapRGB(Uint8 red,Uint8 grn,Uint8 blu)924 Uint32 screenMapRGB(Uint8 red, Uint8 grn, Uint8 blu)
925 {
926 return SDL_MapRGB(Screen->format, red, grn, blu);
927 }
928
screenZoomOut(int factor)929 void screenZoomOut(int factor)
930 {
931 if (factor)
932 Zoom *= factor;
933 }
934
screenZoomIn(int factor)935 void screenZoomIn(int factor)
936 {
937 if (factor)
938 Zoom /= factor;
939 }
940
screenCapture(char * fname,SDL_Rect * rect)941 void screenCapture(char *fname, SDL_Rect *rect)
942 {
943 png_structp png_ptr = 0;
944 png_infop info_ptr = 0;
945 Uint32 *spix = 0;
946 Uint8 *row_pointer = 0;
947 int si, spitch;
948
949 /* Open the destination file. */
950 FILE *fp = fopen(fname, "wb");
951 if (!fp) {
952 return;
953 }
954
955 /* Setup PNG for writing. */
956 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
957 (png_voidp)0,
958 0,
959 0);
960 if (!png_ptr) {
961 goto done;
962 return;
963 }
964
965 info_ptr = png_create_info_struct(png_ptr);
966 if (!info_ptr) {
967 goto done;
968 }
969
970 if (setjmp(png_jmpbuf(png_ptr))) {
971 warn("screenCapture: PNG error!\n");
972 goto done;
973 }
974
975 png_init_io(png_ptr, fp);
976
977 /* Setup the image header. */
978 png_set_IHDR(png_ptr, info_ptr,
979 MAP_W,
980 MAP_H,
981 8,
982 PNG_COLOR_TYPE_RGB,
983 PNG_INTERLACE_NONE,
984 PNG_COMPRESSION_TYPE_DEFAULT,
985 PNG_FILTER_TYPE_DEFAULT);
986
987 /* Write the header. */
988 png_write_info(png_ptr, info_ptr);
989
990 /* TODO: if Screen is not in correct format, convert it to
991 * a suitable temp surface (maybe a row at the time?).
992 */
993 assert(Screen->format->BytesPerPixel==4);
994 /* Grab the screen pixels. */
995 spix = (Uint32*)Screen->pixels;
996 spitch = Screen->pitch / Screen->format->BytesPerPixel;
997
998 /* Allocate the row buffer. I copy pixels to an intermediate row buffer
999 * so that I can handle different pixel formats (eg, RGBA vs ARGB,
1000 * etc). */
1001 row_pointer = (Uint8*)malloc(rect->w * 3);
1002 assert(row_pointer);
1003
1004 for (int y = 0; y < rect->h; y++) {
1005
1006 /* Copy the SDL pixels into the intermediate buffer. PNG
1007 * expects pixels in RGB order. */
1008 Uint8 *dpix = row_pointer;
1009 for (int x = 0; x < rect->w; x++) {
1010 si = (y + rect->y) * spitch + (x + rect->x);
1011 *dpix++ = ((spix[si] & Screen->format->Rmask)
1012 >> Screen->format->Rshift);
1013 *dpix++ = ((spix[si] & Screen->format->Gmask)
1014 >> Screen->format->Gshift);
1015 *dpix++ = ((spix[si] & Screen->format->Bmask)
1016 >> Screen->format->Bshift);
1017 }
1018
1019 /* Write the row to PNG. */
1020 png_write_row(png_ptr, row_pointer);
1021 }
1022
1023 png_write_end(png_ptr, 0);
1024
1025 done:
1026 if (row_pointer) {
1027 free(row_pointer);
1028 }
1029
1030 if (png_ptr) {
1031 png_destroy_write_struct(&png_ptr, &info_ptr);
1032 }
1033
1034 fclose(fp);
1035
1036 }
1037