2 // nazghul - an old-school RPG engine
3 // Copyright (C) 2002, 2003 Gordon McNutt
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)
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
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
20 // gmcnutt@users.sourceforge.net
30 #include "nazghul.h" // for FullScreenMode
37 #include <SDL_image.h>
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
45 /* Frame image indices */
62 #define FRAME_NUM_SPRITES 16
64 /* Enable this to dump surfaces and video info */
66 #define SCREEN_DEBUG 0
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];
74 static char screen_buf[128];
94 SDL_Color fontWhite = { 0xff, 0xff, 0xff, 0x00 };
95 SDL_Color fontBlack = { 0, 0, 0, 0 };
97 static void scaled_blit(SDL_Surface * source, SDL_Rect * from,
98 SDL_Surface * dest, SDL_Rect * to);
100 void screenInitColors(void)
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);
120 void dump_SDL_PixelFormat(SDL_PixelFormat *fmt)
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);
141 void dump_SDL_VideoInfo(const SDL_VideoInfo *fmt)
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);
157 void dump_SDL_Surface(SDL_Surface *surf)
159 printf("Surface Info:\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",
200 printf(" refcount: %d\n", surf->refcount);
201 dump_SDL_PixelFormat(surf->format);
205 void screenInitScreen(void)
207 Uint32 flags = SDL_ANYFORMAT;
208 const SDL_VideoInfo *fmt;
210 const int SCREEN_BPP = 0; /* use display BPP */
212 if (SDL_Init(SDL_INIT_VIDEO) < 0) {
213 perror_sdl("SDL_Init");
218 fmt = SDL_GetVideoInfo();
220 perror_sdl("SDL_GetVideoInfo");
225 dump_SDL_VideoInfo(fmt);
228 if (fmt->blit_hw_CC && fmt->blit_fill) {
229 flags |= SDL_HWSURFACE;
230 flags |= SDL_DOUBLEBUF;
232 if (FullScreenMode) {
233 flags |= SDL_FULLSCREEN;
236 Screen = SDL_SetVideoMode(SCREEN_W, SCREEN_H, SCREEN_BPP, flags);
238 perror_sdl("SDL_SetVideoMode");
243 printf("Video initialized to...\n");
244 dump_SDL_Surface(Screen);
247 SDL_WM_SetCaption(APPLICATION_NAME, APPLICATION_NAME);
250 void screen_fade_surface(SDL_Surface * surf, int fade_level)
258 assert(surf->format->BitsPerPixel == 8);
263 pix = (Uint8 *) surf->pixels;
264 trans = (Uint8) surf->format->colorkey;
266 for (y = 0; y < surf->h; y++) {
267 base = y * surf->pitch;
269 for (x = 0; x < surf->w; x++) {
272 if (pix[i] != trans) {
276 } else if (pix[i] != trans) {
282 assert(surf->format->BitsPerPixel == 8);
284 screen_fade_surface(surf, fade_level - 1);
287 static SDL_Surface *create_shader(int fade_level)
291 shader = screenCreateSurface(SHADER_W, SHADER_H);
295 SDL_FillRect(shader, NULL, SDL_MapRGBA(shader->format, 0, 0, 0, 0));
297 if (shader->format->palette != NULL) {
298 SDL_LockSurface(shader);
299 screen_fade_surface(shader, fade_level);
300 SDL_UnlockSurface(shader);
306 void screenInitShader(void)
310 n = (Screen->format->BitsPerPixel == 8) ? N_SHADERS : 1;
312 for (i = 0; i < n; i++) {
313 Shaders[i] = create_shader(i);
317 void screenInitHighlight(void)
319 Highlight = screenCreateSurface(SHADER_W, SHADER_H);
320 assert(Highlight != NULL);
322 SDL_FillRect(Highlight, NULL, SDL_MapRGBA(Highlight->format, 255, 255, 255, 0));
324 if (Highlight->format->palette != NULL) {
325 SDL_LockSurface(Highlight);
326 screen_fade_surface(Highlight, 4);
327 SDL_UnlockSurface(Highlight);
331 static void screenInitFrame(void)
334 char *fname = cfg_get("frame-image-filename");
335 struct images *ss_frame = 0;
338 warn("No frame image filename!");
342 memset(FrameSprites, 0, sizeof(FrameSprites));
344 ss_frame = images_new(0, 16, 16, 4, 4, 0, 0, fname);
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]);
358 screenInitHighlight();
362 SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY,
363 SDL_DEFAULT_REPEAT_INTERVAL);
368 void screenErase(SDL_Rect * rect)
370 SDL_FillRect(Screen, rect, Black);
373 void screenFill(SDL_Rect * rect, Uint32 color)
375 SDL_Rect tmp = *rect;
378 SDL_FillRect(Screen, rect, color);
381 void screenUpdate(SDL_Rect * rect)
384 SDL_UpdateRect(Screen, rect->x, rect->y, rect->w, rect->h);
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)
396 static void scaled_blit_32bpp(SDL_Surface * source, SDL_Rect * from,
397 SDL_Surface * dest, SDL_Rect * to,
398 int spitch, int dpitch)
400 int dx, dy, di, sx, sy, si;
403 d = (Uint32 *) dest->pixels;
404 s = (Uint32 *) source->pixels;
406 for (dy = 0; dy < to->h; dy++) {
408 for (dx = 0; dx < to->w; dx++) {
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]))
418 static void scaled_blit_16bpp(SDL_Surface * source, SDL_Rect * from,
419 SDL_Surface * dest, SDL_Rect * to,
420 int spitch, int dpitch)
422 int dx, dy, di, sx, sy, si;
425 d = (Uint16 *) dest->pixels;
426 s = (Uint16 *) source->pixels;
428 for (dy = 0; dy < to->h; dy++) {
430 for (dx = 0; dx < to->w; dx++) {
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]))
440 static void scaled_blit_8bpp(SDL_Surface * source, SDL_Rect * from,
441 SDL_Surface * dest, SDL_Rect * to,
442 int spitch, int dpitch)
444 int dx, dy, di, sx, sy, si;
447 d = (Uint8 *) dest->pixels;
448 s = (Uint8 *) source->pixels;
450 for (dy = 0; dy < to->h; dy++) {
452 for (dx = 0; dx < to->w; dx++) {
454 di = (dy + to->y) * dpitch + (dx + to->x);
455 si = (sy + from->y) * spitch + (sx + from->x);
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. */
465 static void scale_then_blit_normal(SDL_Surface * source, SDL_Rect * from,
466 SDL_Surface * dest, SDL_Rect * to)
468 SDL_Surface *tmp = 0;
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);
482 perror_sdl("SDL_CreateRGBSurface");
486 /* Setup a rect for the tmp surface. */
492 /* Do a scaled_blit from the source to the temporary surface. */
493 scaled_blit(source, from, tmp, &rect);
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
500 screenBlit(tmp, &rect, to);
503 /* Free the tmp surface. */
504 SDL_FreeSurface(tmp);
507 static void scaled_blit(SDL_Surface * source, SDL_Rect * from,
508 SDL_Surface * dest, SDL_Rect * to)
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
517 if (source->format->BitsPerPixel != dest->format->BitsPerPixel
518 || source->format->Amask != dest->format->Amask
520 scale_then_blit_normal(source, from, dest, to);
527 dpitch = dest->pitch / dest->format->BytesPerPixel;
528 spitch = source->pitch / source->format->BytesPerPixel;
530 if (SDL_LockSurface(dest) < 0)
533 switch (dest->format->BitsPerPixel) {
535 scaled_blit_32bpp(source, from, dest, to, spitch, dpitch);
538 scaled_blit_16bpp(source, from, dest, to, spitch, dpitch);
541 scaled_blit_8bpp(source, from, dest, to, spitch, dpitch);
548 SDL_UnlockSurface(dest);
551 void screenBlit(SDL_Surface * source, SDL_Rect * from, SDL_Rect * to)
553 /* Clipping is really only needed for wave sprites right now. If the
554 * following proves to be too expensive on slow machines... */
557 SDL_SetClipRect(Screen, &_to);
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
573 scaled_blit(source, from, Screen, &_to);
575 if (SDL_BlitSurface(source, from, Screen, &_to) < 0)
576 perror_sdl("SDL_BlitSurface");
578 SDL_SetClipRect(Screen, 0);
580 SDL_SetClipRect(Screen, to);
581 if (SDL_BlitSurface(source, from, Screen, NULL) < 0)
582 perror_sdl("SDL_BlitSurface");
583 SDL_SetClipRect(Screen, 0);
587 int screenWidth(void)
592 int screenHeight(void)
597 SDL_PixelFormat *screenFormat(void)
599 return Screen->format;
602 void screenFlash(SDL_Rect * rect, int mdelay, Uint32 color)
604 screenFill(rect, color);
606 //usleep(mdelay * 1000);
610 void screenPrint(SDL_Rect * rect, int flags, const char *fmt, ...)
616 int alen, slen, stop;
618 /* Print the string to a buffer. */
620 vsnprintf(screen_buf, sizeof(screen_buf), fmt, args);
623 slen = strlen(screen_buf);
624 alen = asciiStrlen(screen_buf);
625 stop = rect->x + (rect->w * ASCII_W);
627 /* If painting on the border then first fill the line with the border
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);
634 /* Calculate offset for center and right-justified cases */
635 if (flags & SP_CENTERED) {
636 int w = alen * ASCII_W;
640 x = (rect->w - w) / 2 + rect->x;
641 } else if (flags & SP_RIGHTJUSTIFIED) {
642 int w = alen * ASCII_W;
646 x = (rect->w - w) + rect->x;
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);
655 /* Paint the characters until we run out or hit the end of the
657 for (i = 0; i < slen && x < stop; i++) {
659 if (asciiPaint(screen_buf[i], x, y, Screen)) {
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);
673 void screen_repaint_frame(void)
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.
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);
688 // Draw the top bar from the sky window to the left edge of the status
690 for (i = SKY_X + SKY_W + BORDER_W; i < STAT_X; i += BORDER_W)
691 sprite_paint(FrameSprites[FRAME_HORZ], 0, i, 0);
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);
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;
701 sprite_paint(FrameSprites[FRAME_HORZ], 0, i, MAP_X + MAP_H);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
762 SDL_Surface *screenCreateSurface(int w, int h)
764 SDL_Surface *surf = NULL, *tmp;
766 tmp = SDL_CreateRGBSurface(Screen->flags,
768 Screen->format->BitsPerPixel,
769 Screen->format->Rmask,
770 Screen->format->Gmask,
771 Screen->format->Bmask,
772 Screen->format->Amask);
774 // surf->format->palette = Screen->format->palette;
777 perror_sdl("SDL_CreateRGBSurface");
781 surf = SDL_DisplayFormat(tmp);
782 SDL_FreeSurface(tmp);
785 perror_sdl("SDL_DisplayFormat");
789 if (surf->format->palette) {
790 SDL_SetColorKey(surf, SDL_SRCCOLORKEY,
791 SDL_MapRGB(surf->format, 0xFF, 0x00, 0xFF));
797 void screenCopy(SDL_Rect * from, SDL_Rect * to, SDL_Surface * dest)
799 if (SDL_BlitSurface(Screen, from, dest, to) < 0)
800 perror_sdl("SDL_BlitSurface");
805 SDL_Rect _from = *from;
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
820 scaled_blit(Screen, &_from, dest, to);
822 if (SDL_BlitSurface(Screen, &_from, dest, to) < 0)
823 perror_sdl("SDL_BlitSurface");
827 void screenShade(SDL_Rect * area, unsigned char amount)
831 assert(area->w <= SHADER_W);
832 assert(area->h <= SHADER_H);
837 if (Screen->format->BitsPerPixel == 8) {
838 shade = Shaders[MAX_SHADER - (amount * MAX_SHADER) / 255];
841 SDL_SetAlpha(shade, SDL_SRCALPHA, amount);
843 screenBlit(shade, NULL, area);
846 void screenHighlightColored(SDL_Rect * area, Uint32 color)
850 // ---------------------------------------------------------------------
852 // ---------------------------------------------------------------------
857 edge.h = HIGHLIGHT_THICKNESS;
859 screenFill(&edge, color);
861 // ---------------------------------------------------------------------
863 // ---------------------------------------------------------------------
866 edge.y = area->y + (area->h/Zoom) - HIGHLIGHT_THICKNESS;
868 edge.h = HIGHLIGHT_THICKNESS;
870 screenFill(&edge, color);
872 // ---------------------------------------------------------------------
874 // ---------------------------------------------------------------------
878 edge.w = HIGHLIGHT_THICKNESS;
881 screenFill(&edge, color);
883 // ---------------------------------------------------------------------
885 // ---------------------------------------------------------------------
887 edge.x = area->x + (area->w/Zoom) - HIGHLIGHT_THICKNESS;
889 edge.w = HIGHLIGHT_THICKNESS;
892 screenFill(&edge, color);
895 void screenHighlight(SDL_Rect *area)
897 screenHighlightColored(area, White);
902 return SDL_LockSurface(Screen);
905 void screenUnlock(void)
907 SDL_UnlockSurface(Screen);
910 /* assumes the pixel value is gotten from screenMapRGB() i.e. safe! */
911 void screenSetPixel(int x, int y, Uint32 color)
913 Uint8 *pix = (Uint8*)(Screen->pixels);
914 pix += y * Screen->pitch + x * Screen->format->BytesPerPixel;
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;
924 Uint32 screenMapRGB(Uint8 red, Uint8 grn, Uint8 blu)
926 return SDL_MapRGB(Screen->format, red, grn, blu);
929 void screenZoomOut(int factor)
935 void screenZoomIn(int factor)
941 void screenCapture(char *fname, SDL_Rect *rect)
943 png_structp png_ptr = 0;
944 png_infop info_ptr = 0;
946 Uint8 *row_pointer = 0;
949 /* Open the destination file. */
950 FILE *fp = fopen(fname, "wb");
955 /* Setup PNG for writing. */
956 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
965 info_ptr = png_create_info_struct(png_ptr);
970 if (setjmp(png_jmpbuf(png_ptr))) {
971 warn("screenCapture: PNG error!\n");
975 png_init_io(png_ptr, fp);
977 /* Setup the image header. */
978 png_set_IHDR(png_ptr, info_ptr,
984 PNG_COMPRESSION_TYPE_DEFAULT,
985 PNG_FILTER_TYPE_DEFAULT);
987 /* Write the header. */
988 png_write_info(png_ptr, info_ptr);
990 /* TODO: if Screen is not in correct format, convert it to
991 * a suitable temp surface (maybe a row at the time?).
993 assert(Screen->format->BytesPerPixel==4);
994 /* Grab the screen pixels. */
995 spix = (Uint32*)Screen->pixels;
996 spitch = Screen->pitch / Screen->format->BytesPerPixel;
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,
1001 row_pointer = (Uint8*)malloc(rect->w * 3);
1002 assert(row_pointer);
1004 for (int y = 0; y < rect->h; y++) {
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);
1019 /* Write the row to PNG. */
1020 png_write_row(png_ptr, row_pointer);
1023 png_write_end(png_ptr, 0);
1031 png_destroy_write_struct(&png_ptr, &info_ptr);