Dropped unused load_surf_with_flags() from sdl2-client.
[freeciv.git] / client / gui-sdl2 / graphics.c
blob249a70156cb50ec261f54f0beb6cd22acbd603d0
1 /***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
14 /***********************************************************************
15 graphics.c - description
16 -------------------
17 begin : Mon Jul 1 2002
18 copyright : (C) 2000 by Michael Speck
19 : (C) 2002 by Rafał Bursig
20 email : Michael Speck <kulkanie@gmx.net>
21 : Rafał Bursig <bursig@poczta.fm>
22 ***********************************************************************/
24 #ifdef HAVE_CONFIG_H
25 #include <fc_config.h>
26 #endif
28 /* SDL2 */
29 #ifdef SDL2_PLAIN_INCLUDE
30 #include <SDL_image.h>
31 #include <SDL_syswm.h>
32 #include <SDL_ttf.h>
33 #else /* SDL2_PLAIN_INCLUDE */
34 #include <SDL2/SDL_image.h>
35 #include <SDL2/SDL_syswm.h>
36 #include <SDL2/SDL_ttf.h>
37 #endif /* SDL2_PLAIN_INCLUDE */
39 /* utility */
40 #include "fcintl.h"
41 #include "log.h"
43 /* client */
44 #include "tilespec.h"
46 /* gui-sdl2 */
47 #include "colors.h"
48 #include "gui_tilespec.h"
49 #include "mapview.h"
50 #include "themebackgrounds.h"
51 #include "themespec.h"
53 #include "graphics.h"
55 /* ------------------------------ */
57 struct main Main;
59 static SDL_Surface *main_surface;
61 static bool render_dirty = TRUE;
63 /**************************************************************************
64 Allocate new gui_layer.
65 **************************************************************************/
66 struct gui_layer *gui_layer_new(int x, int y, SDL_Surface *surface)
68 struct gui_layer *result;
70 result = fc_calloc(1, sizeof(struct gui_layer));
72 result->dest_rect = (SDL_Rect){x, y, 0, 0};
73 result->surface = surface;
75 return result;
78 /**************************************************************************
79 Free resources associated with gui_layer.
80 **************************************************************************/
81 void gui_layer_destroy(struct gui_layer **gui_layer)
83 FREESURFACE((*gui_layer)->surface);
84 FC_FREE(*gui_layer);
87 /**************************************************************************
88 Get surface gui_layer.
89 **************************************************************************/
90 struct gui_layer *get_gui_layer(SDL_Surface *surface)
92 int i = 0;
94 while ((i < Main.guis_count) && Main.guis[i]) {
95 if (Main.guis[i]->surface == surface) {
96 return Main.guis[i];
98 i++;
101 return NULL;
104 /**************************************************************************
105 Buffer allocation function.
106 This function is call by "create_window(...)" function and allocate
107 buffer layer for this function.
109 Pointer for this buffer is put in buffer array on last position that
110 flush functions will draw this layer last.
111 **************************************************************************/
112 struct gui_layer *add_gui_layer(int width, int height)
114 struct gui_layer *gui_layer = NULL;
115 SDL_Surface *pBuffer;
117 pBuffer = create_surf(width, height, SDL_SWSURFACE);
118 gui_layer = gui_layer_new(0, 0, pBuffer);
120 /* add to buffers array */
121 if (Main.guis) {
122 int i;
124 /* find NULL element */
125 for (i = 0; i < Main.guis_count; i++) {
126 if (!Main.guis[i]) {
127 Main.guis[i] = gui_layer;
128 return gui_layer;
131 Main.guis_count++;
132 Main.guis = fc_realloc(Main.guis, Main.guis_count * sizeof(struct gui_layer *));
133 Main.guis[Main.guis_count - 1] = gui_layer;
134 } else {
135 Main.guis = fc_calloc(1, sizeof(struct gui_layer *));
136 Main.guis[0] = gui_layer;
137 Main.guis_count = 1;
140 return gui_layer;
143 /**************************************************************************
144 Free buffer layer ( call by popdown_window_group_dialog(...) funct )
145 Funct. free buffer layer and cleare buffer array entry.
146 **************************************************************************/
147 void remove_gui_layer(struct gui_layer *gui_layer)
149 int i;
151 for (i = 0; i < Main.guis_count - 1; i++) {
152 if (Main.guis[i] && (Main.guis[i]== gui_layer)) {
153 gui_layer_destroy(&Main.guis[i]);
154 Main.guis[i] = Main.guis[i + 1];
155 Main.guis[i + 1] = NULL;
156 } else {
157 if (!Main.guis[i]) {
158 Main.guis[i] = Main.guis[i + 1];
159 Main.guis[i + 1] = NULL;
164 if (Main.guis[Main.guis_count - 1]) {
165 gui_layer_destroy(&Main.guis[Main.guis_count - 1]);
169 /**************************************************************************
170 Adjust dest_rect according to gui_layer.
171 **************************************************************************/
172 void screen_rect_to_layer_rect(struct gui_layer *gui_layer,
173 SDL_Rect *dest_rect)
175 if (gui_layer) {
176 dest_rect->x = dest_rect->x - gui_layer->dest_rect.x;
177 dest_rect->y = dest_rect->y - gui_layer->dest_rect.y;
181 /* ============ Freeciv sdl graphics function =========== */
183 /**************************************************************************
184 Execute alphablit.
185 **************************************************************************/
186 int alphablit(SDL_Surface *src, SDL_Rect *srcrect,
187 SDL_Surface *dst, SDL_Rect *dstrect,
188 unsigned char alpha_mod)
190 int ret;
192 if (src == NULL || dst == NULL) {
193 return 1;
196 SDL_SetSurfaceAlphaMod(src, alpha_mod);
198 ret = SDL_BlitSurface(src, srcrect, dst, dstrect);
200 if (ret) {
201 log_error("SDL_BlitSurface() fails: %s", SDL_GetError());
204 return ret;
207 /**************************************************************************
208 Execute alphablit to the main surface
209 **************************************************************************/
210 int screen_blit(SDL_Surface *src, SDL_Rect *srcrect, SDL_Rect *dstrect,
211 unsigned char alpha_mod)
213 render_dirty = TRUE;
214 return alphablit(src, srcrect, main_surface, dstrect, alpha_mod);
217 /**************************************************************************
218 Create new surface (pRect->w x pRect->h size) and copy pRect area of
219 pSource.
220 if pRect == NULL then create copy of entire pSource.
221 **************************************************************************/
222 SDL_Surface *crop_rect_from_surface(SDL_Surface *pSource,
223 SDL_Rect *pRect)
225 SDL_Surface *pNew = create_surf_with_format(pSource->format,
226 pRect ? pRect->w : pSource->w,
227 pRect ? pRect->h : pSource->h,
228 SDL_SWSURFACE);
230 if (alphablit(pSource, pRect, pNew, NULL, 255) != 0) {
231 FREESURFACE(pNew);
233 return NULL;
236 return pNew;
239 /**************************************************************************
240 Reduce the alpha of the final surface proportional to the alpha of the mask.
241 Thus if the mask has 50% alpha the final image will be reduced by 50% alpha.
243 mask_offset_x, mask_offset_y is the offset of the mask relative to the
244 origin of the source image. The pixel at (mask_offset_x,mask_offset_y)
245 in the mask image will be used to clip pixel (0,0) in the source image
246 which is pixel (-x,-y) in the new image.
247 **************************************************************************/
248 SDL_Surface *mask_surface(SDL_Surface *pSrc, SDL_Surface *pMask,
249 int mask_offset_x, int mask_offset_y)
251 SDL_Surface *pDest = NULL;
252 int row, col;
253 Uint32 *pSrc_Pixel = NULL;
254 Uint32 *pDest_Pixel = NULL;
255 Uint32 *pMask_Pixel = NULL;
256 unsigned char src_alpha, mask_alpha;
258 pDest = copy_surface(pSrc);
260 lock_surf(pSrc);
261 lock_surf(pMask);
262 lock_surf(pDest);
264 pSrc_Pixel = (Uint32 *)pSrc->pixels;
265 pDest_Pixel = (Uint32 *)pDest->pixels;
267 for (row = 0; row < pSrc->h; row++) {
268 pMask_Pixel = (Uint32 *)pMask->pixels
269 + pMask->w * (row + mask_offset_y)
270 + mask_offset_x;
272 for (col = 0; col < pSrc->w; col++) {
273 src_alpha = (*pSrc_Pixel & pSrc->format->Amask) >> pSrc->format->Ashift;
274 mask_alpha = (*pMask_Pixel & pMask->format->Amask) >> pMask->format->Ashift;
276 *pDest_Pixel = (*pSrc_Pixel & ~pSrc->format->Amask)
277 | (((src_alpha * mask_alpha) / 255) << pDest->format->Ashift);
279 pSrc_Pixel++; pDest_Pixel++; pMask_Pixel++;
283 unlock_surf(pDest);
284 unlock_surf(pMask);
285 unlock_surf(pSrc);
287 return pDest;
290 /**************************************************************************
291 Load a surface from file putting it in software mem.
292 **************************************************************************/
293 SDL_Surface *load_surf(const char *pFname)
295 SDL_Surface *pBuf;
297 if (!pFname) {
298 return NULL;
301 if ((pBuf = IMG_Load(pFname)) == NULL) {
302 log_error(_("load_surf: Failed to load graphic file %s!"), pFname);
304 return NULL;
307 #if 0
308 if (Main.screen) {
309 SDL_Surface *pNew_sur;
311 if ((pNew_sur = SDL_ConvertSurfaceFormat(pBuf, SDL_PIXELFORMAT_RGBA4444, 0)) == NULL) {
312 log_error(_("load_surf: Unable to convert file %s "
313 "into screen's format!"), pFname);
314 } else {
315 FREESURFACE(pBuf);
317 return pNew_sur;
320 #endif /* 0 */
322 return pBuf;
325 /**************************************************************************
326 create an surface with format
327 MUST NOT BE USED IF NO SDLSCREEN IS SET
328 **************************************************************************/
329 SDL_Surface *create_surf_with_format(SDL_PixelFormat *pf,
330 int width, int height,
331 Uint32 flags)
333 SDL_Surface *surf = SDL_CreateRGBSurface(flags, width, height,
334 pf->BitsPerPixel,
335 pf->Rmask,
336 pf->Gmask,
337 pf->Bmask, pf->Amask);
339 if (surf == NULL) {
340 log_error(_("Unable to create Sprite (Surface) of size "
341 "%d x %d %d Bits in format %d"),
342 width, height, pf->BitsPerPixel, flags);
343 return NULL;
346 return surf;
349 /**************************************************************************
350 Create surface with the same format as main window
351 **************************************************************************/
352 SDL_Surface *create_surf(int width, int height, Uint32 flags)
354 return create_surf_with_format(main_surface->format, width, height, flags);
357 /**************************************************************************
358 Convert surface to the main window format.
359 **************************************************************************/
360 SDL_Surface *convert_surf(SDL_Surface *surf_in)
362 return SDL_ConvertSurface(surf_in, main_surface->format, 0);
365 /**************************************************************************
366 create an surface with screen format and fill with color.
367 if pColor == NULL surface is filled with transparent white A = 128
368 **************************************************************************/
369 SDL_Surface *create_filled_surface(Uint16 w, Uint16 h, Uint32 iFlags,
370 SDL_Color *pColor)
372 SDL_Surface *pNew;
373 SDL_Color color = {255, 255, 255, 128};
375 pNew = create_surf(w, h, iFlags);
377 if (!pNew) {
378 return NULL;
381 if (!pColor) {
382 /* pColor->unused == ALPHA */
383 pColor = &color;
386 SDL_FillRect(pNew, NULL,
387 SDL_MapRGBA(pNew->format, pColor->r, pColor->g, pColor->b,
388 pColor->a));
390 if (pColor->a != 255) {
391 SDL_SetSurfaceAlphaMod(pNew, pColor->a);
394 return pNew;
397 /**************************************************************************
398 fill surface with (0, 0, 0, 0), so the next blitting operation can set
399 the per pixel alpha
400 **************************************************************************/
401 int clear_surface(SDL_Surface *pSurf, SDL_Rect *dstrect)
403 /* SDL_FillRect might change the rectangle, so we create a copy */
404 if (dstrect) {
405 SDL_Rect _dstrect = *dstrect;
407 return SDL_FillRect(pSurf, &_dstrect, SDL_MapRGBA(pSurf->format, 0, 0, 0, 0));
408 } else {
409 return SDL_FillRect(pSurf, NULL, SDL_MapRGBA(pSurf->format, 0, 0, 0, 0));
413 /**************************************************************************
414 blit entire src [SOURCE] surface to destination [DEST] surface
415 on position : [iDest_x],[iDest_y] using it's actual alpha and
416 color key settings.
417 **************************************************************************/
418 int blit_entire_src(SDL_Surface * pSrc, SDL_Surface * pDest,
419 Sint16 iDest_x, Sint16 iDest_y)
421 SDL_Rect dest_rect = { iDest_x, iDest_y, 0, 0 };
423 return alphablit(pSrc, NULL, pDest, &dest_rect, 255);
427 * this is center main application window function
428 * currently it work only for X but problem is that such
429 * functions will be needed by others enviroments.
430 * ( for X it's make by settings "SDL_VIDEO_CENTERED" enviroment )
432 int center_main_window_on_screen(void)
434 #if 0
435 SDL_SysWMinfo myinfo;
437 SDL_VERSION(&myinfo.version);
438 if (SDL_GetWMInfo(&myinfo) > 0)
440 #ifdef WIN32_NATIVE
442 /* Port ME - Write center window code with WinAPI instructions */
444 return 0;
445 #else /* WIN32_NATIVE */
447 #if 0
448 /* this code is for X and is only example what should be write to other
449 enviroments */
450 Screen *defscr;
451 Display *d = myinfo.info.x11.display;
453 myinfo.info.x11.lock_func();
454 defscr = DefaultScreenOfDisplay(d);
455 XMoveWindow(d, myinfo.info.x11.wmwindow,
456 (defscr->width - Main.screen->w) / 2,
457 (defscr->height - Main.screen->h) / 2);
458 myinfo.info.x11.unlock_func();
459 #endif /* 0 */
460 return 0;
461 #endif /* WIN32_NATIVE */
463 return -1;
464 #endif /* 0 */
466 return 0;
469 /**************************************************************************
470 get pixel
471 Return the pixel value at (x, y)
472 NOTE: The surface must be locked before calling this!
473 **************************************************************************/
474 Uint32 getpixel(SDL_Surface *pSurface, Sint16 x, Sint16 y)
476 if (!pSurface) {
477 return 0x0;
480 switch (pSurface->format->BytesPerPixel) {
481 case 1:
482 return *(Uint8 *) ((Uint8 *) pSurface->pixels + y * pSurface->pitch + x);
484 case 2:
485 return *((Uint16 *)pSurface->pixels + y * pSurface->pitch / sizeof(Uint16) + x);
487 case 3:
489 /* Here ptr is the address to the pixel we want to retrieve */
490 Uint8 *ptr =
491 (Uint8 *) pSurface->pixels + y * pSurface->pitch + x * 3;
493 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
494 return ptr[0] << 16 | ptr[1] << 8 | ptr[2];
495 } else {
496 return ptr[0] | ptr[1] << 8 | ptr[2] << 16;
499 case 4:
500 return *((Uint32 *)pSurface->pixels + y * pSurface->pitch / sizeof(Uint32) + x);
502 default:
503 return 0; /* shouldn't happen, but avoids warnings */
507 /**************************************************************************
508 get first pixel
509 Return the pixel value at (0, 0)
510 NOTE: The surface must be locked before calling this!
511 **************************************************************************/
512 Uint32 get_first_pixel(SDL_Surface *pSurface)
514 if (!pSurface) {
515 return 0;
518 switch (pSurface->format->BytesPerPixel) {
519 case 1:
520 return *((Uint8 *)pSurface->pixels);
522 case 2:
523 return *((Uint16 *)pSurface->pixels);
525 case 3:
527 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
528 return (((Uint8 *)pSurface->pixels)[0] << 16)
529 | (((Uint8 *)pSurface->pixels)[1] << 8)
530 | ((Uint8 *)pSurface->pixels)[2];
531 } else {
532 return ((Uint8 *)pSurface->pixels)[0]
533 | (((Uint8 *)pSurface->pixels)[1] << 8)
534 | (((Uint8 *)pSurface->pixels)[2] << 16);
537 case 4:
538 return *((Uint32 *)pSurface->pixels);
540 default:
541 return 0; /* shouldn't happen, but avoids warnings */
545 /* ===================================================================== */
547 /**************************************************************************
548 initialize sdl with Flags
549 **************************************************************************/
550 void init_sdl(int iFlags)
552 bool error;
554 Main.screen = NULL;
555 Main.guis = NULL;
556 Main.gui = NULL;
557 Main.map = NULL;
558 Main.dummy = NULL; /* can't create yet -- hope we don't need it */
559 Main.rects_count = 0;
560 Main.guis_count = 0;
562 if (SDL_WasInit(SDL_INIT_AUDIO)) {
563 error = (SDL_InitSubSystem(iFlags) < 0);
564 } else {
565 error = (SDL_Init(iFlags) < 0);
567 if (error) {
568 log_fatal(_("Unable to initialize SDL2 library: %s"), SDL_GetError());
569 exit(EXIT_FAILURE);
572 atexit(SDL_Quit);
574 /* Initialize the TTF library */
575 if (TTF_Init() < 0) {
576 log_fatal(_("Unable to initialize SDL2_ttf library: %s"), SDL_GetError());
577 exit(EXIT_FAILURE);
580 atexit(TTF_Quit);
583 /**************************************************************************
584 Free screen buffers
585 **************************************************************************/
586 void quit_sdl(void)
588 FC_FREE(Main.guis);
589 gui_layer_destroy(&Main.gui);
590 FREESURFACE(Main.map);
591 FREESURFACE(Main.dummy);
594 /**************************************************************************
595 Switch to passed video mode.
596 **************************************************************************/
597 int set_video_mode(int iWidth, int iHeight, int iFlags)
599 unsigned int flags;
601 Main.screen = SDL_CreateWindow(_("SDL2 Client for Freeciv"),
602 SDL_WINDOWPOS_UNDEFINED,
603 SDL_WINDOWPOS_UNDEFINED,
604 iWidth, iHeight,
607 main_surface = SDL_CreateRGBSurface(0, iWidth, iHeight, 32,
608 #if SDL_BYTEORDER != SDL_LIL_ENDIAN
609 0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF
610 #else
611 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000
612 #endif
615 Main.map = SDL_CreateRGBSurface(0, iWidth, iHeight, 32,
616 #if SDL_BYTEORDER != SDL_LIL_ENDIAN
617 0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF
618 #else
619 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000
620 #endif
623 if (gui_options.gui_sdl2_swrenderer) {
624 flags = SDL_RENDERER_SOFTWARE;
625 } else {
626 flags = 0;
629 Main.renderer = SDL_CreateRenderer(Main.screen, -1, flags);
631 Main.maintext = SDL_CreateTexture(Main.renderer,
632 SDL_PIXELFORMAT_ARGB8888,
633 SDL_TEXTUREACCESS_STREAMING,
634 iWidth, iHeight);
636 #if 0
637 /* find best bpp */
638 int iDepth = SDL_GetVideoInfo()->vfmt->BitsPerPixel;
640 /* if screen does exist check if this is mayby
641 exactly the same resolution then return 1 */
642 if (Main.screen) {
643 if (Main.screen->w == iWidth && Main.screen->h == iHeight) {
644 if ((Main.screen->flags & SDL_FULLSCREEN)
645 && (iFlags & SDL_FULLSCREEN)) {
646 return 1;
651 /* Check to see if a particular video mode is supported */
652 if ((iDepth = SDL_VideoModeOK(iWidth, iHeight, iDepth, iFlags)) == 0) {
653 log_error(_("No available mode for this resolution : %d x %d %d bpp"),
654 iWidth, iHeight, iDepth);
656 log_debug(_("Setting default resolution to : 640 x 480 16 bpp SW"));
658 Main.screen = SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE);
659 } else { /* set video mode */
660 if ((Main.screen = SDL_SetVideoMode(iWidth, iHeight,
661 iDepth, iFlags)) == NULL) {
662 log_error(_("Unable to set this resolution: %d x %d %d bpp %s"),
663 iWidth, iHeight, iDepth, SDL_GetError());
665 exit(-30);
668 log_debug(_("Setting resolution to: %d x %d %d bpp"),
669 iWidth, iHeight, iDepth);
672 /* Create a dummy surface to be used when sprites are missing, etc.
673 * Various things (such as zoomSurfaceRGBA() don't cope well with a
674 * zero-sized surface, so we use a transparent 1x1 surface. */
675 FREESURFACE(Main.dummy);
676 Main.dummy = create_surf(1, 1, SDL_SWSURFACE);
678 FREESURFACE(Main.map);
679 Main.map = SDL_DisplayFormat(Main.screen);
681 #endif /* 0 */
683 if (Main.gui) {
684 FREESURFACE(Main.gui->surface);
685 Main.gui->surface = create_surf(iWidth, iHeight, SDL_SWSURFACE);
686 } else {
687 Main.gui = add_gui_layer(iWidth, iHeight);
690 clear_surface(Main.gui->surface, NULL);
692 return 0;
695 /**************************************************************************
696 Render from main surface with screen renderer.
697 **************************************************************************/
698 void update_main_screen(void)
700 if (render_dirty) {
701 SDL_UpdateTexture(Main.maintext, NULL,
702 main_surface->pixels, main_surface->pitch);
703 SDL_RenderClear(Main.renderer);
704 SDL_RenderCopy(Main.renderer, Main.maintext, NULL, NULL);
705 SDL_RenderPresent(Main.renderer);
707 render_dirty = FALSE;
711 /**************************************************************************
712 Return width of the main window
713 **************************************************************************/
714 int main_window_width(void)
716 return main_surface->w;
719 /**************************************************************************
720 Return height of the main window
721 **************************************************************************/
722 int main_window_height(void)
724 return main_surface->h;
727 /**************************************************************************
728 Fill Rect with RGBA color
729 **************************************************************************/
730 #define MASK565 0xf7de
731 #define MASK555 0xfbde
733 /* 50% alpha (128) */
734 #define BLEND16_50( d, s , mask ) \
735 (((( s & mask ) + ( d & mask )) >> 1) + ( s & d & ( ~mask & 0xffff)))
737 #define BLEND2x16_50( d, s , mask ) \
738 (((( s & (mask | mask << 16)) + ( d & ( mask | mask << 16 ))) >> 1) + \
739 ( s & d & ( ~(mask | mask << 16))))
741 /**************************************************************************
742 Fill rectangle for "565" format surface
743 **************************************************************************/
744 static int __FillRectAlpha565(SDL_Surface *pSurface, SDL_Rect *pRect,
745 SDL_Color *pColor)
747 Uint32 y, end;
748 Uint32 *start;
749 Uint32 *pixel;
750 register Uint32 D, S =
751 SDL_MapRGB(pSurface->format, pColor->r, pColor->g, pColor->b);
752 register Uint32 A = pColor->a >> 3;
754 S &= 0xFFFF;
756 lock_surf(pSurface);
757 if (pRect == NULL) {
758 end = pSurface->w * pSurface->h;
759 pixel = pSurface->pixels;
760 if (A == 16) { /* A == 128 >> 3 */
761 /* this code don't work (A == 128) */
762 if (end & 0x1) { /* end % 2 */
763 D = *pixel;
764 *pixel++ = BLEND16_50(D, S, MASK565);
765 end--;
768 S = S | S << 16;
769 for (y = 0; y < end; y += 2) {
770 D = *(Uint32 *) pixel;
771 *(Uint32 *) pixel = BLEND2x16_50(D, S, MASK565);
772 pixel += 2;
774 } else {
775 S = (S | S << 16) & 0x07e0f81f;
776 DUFFS_LOOP8(
778 D = *pixel;
779 D = (D | D << 16) & 0x07e0f81f;
780 D += (S - D) * A >> 5;
781 D &= 0x07e0f81f;
782 *pixel++ = (D | (D >> 16)) & 0xFFFF;
783 }, end);
785 } else {
786 /* correct pRect size */
787 if (pRect->x < 0) {
788 pRect->w += pRect->x;
789 pRect->x = 0;
790 } else {
791 if (pRect->x >= pSurface->w - pRect->w) {
792 pRect->w = pSurface->w - pRect->x;
796 if (pRect->y < 0) {
797 pRect->h += pRect->y;
798 pRect->y = 0;
799 } else {
800 if (pRect->y >= pSurface->h - pRect->h) {
801 pRect->h = pSurface->h - pRect->y;
805 start = pixel = (Uint32 *) pSurface->pixels +
806 (pRect->y * pSurface->pitch) + pRect->x / 2;
808 if (A == 16) { /* A == 128 >> 3 */
809 /* this code don't work (A == 128) */
810 S = S | S << 16;
811 for (y = 0; y < pRect->h; y++) {
812 end = 0;
814 if (pRect->w & 0x1) {
815 D = *pixel;
816 *pixel++ = BLEND16_50(D, (S & 0xFFFF), MASK565);
817 end++;
820 for (; end < pRect->w; end += 2) {
821 D = *(Uint32 *) pixel;
822 *(Uint32 *) pixel = BLEND2x16_50(D, S, MASK565);
823 pixel += 2;
826 pixel = start + pSurface->pitch;
827 start = pixel;
829 } else {
830 y = 0;
831 S = (S | S << 16) & 0x07e0f81f;
832 y = pRect->h;
833 end = pRect->w;
835 while (y--) {
836 DUFFS_LOOP8(
838 D = *pixel;
839 D = (D | D << 16) & 0x07e0f81f;
840 D += (S - D) * A >> 5;
841 D &= 0x07e0f81f;
842 *pixel++ = (D | (D >> 16)) & 0xFFFF;
843 }, end);
845 pixel = start + pSurface->pitch;
846 start = pixel;
847 } /* while */
852 unlock_surf(pSurface);
853 return 0;
856 /**************************************************************************
857 Fill rectangle for "555" format surface
858 **************************************************************************/
859 static int __FillRectAlpha555(SDL_Surface *pSurface, SDL_Rect *pRect,
860 SDL_Color *pColor)
862 Uint32 y, end;
863 Uint32 *start, *pixel;
864 register Uint32 D, S =
865 SDL_MapRGB(pSurface->format, pColor->r, pColor->g, pColor->b);
866 register Uint32 A = pColor->a >> 3;
868 S &= 0xFFFF;
870 lock_surf(pSurface);
872 if (pRect == NULL) {
873 end = pSurface->w * pSurface->h;
874 pixel = pSurface->pixels;
875 if (A == 16) { /* A == 128 >> 3 */
876 if (end & 0x1) {
877 D = *pixel;
878 *pixel++ = BLEND16_50(D, S, MASK555);
879 end--;
882 S = S | S << 16;
883 for (y = 0; y < end; y += 2) {
884 D = *pixel;
885 *pixel = BLEND2x16_50(D, S, MASK555);
886 pixel += 2;
888 } else {
889 S = (S | S << 16) & 0x03e07c1f;
890 DUFFS_LOOP8(
892 D = *pixel;
893 D = (D | D << 16) & 0x03e07c1f;
894 D += (S - D) * A >> 5;
895 D &= 0x03e07c1f;
896 *pixel++ = (D | (D >> 16)) & 0xFFFF;
897 }, end);
899 } else {
900 /* correct pRect size */
901 if (pRect->x < 0) {
902 pRect->w += pRect->x;
903 pRect->x = 0;
904 } else {
905 if (pRect->x >= pSurface->w - pRect->w) {
906 pRect->w = pSurface->w - pRect->x;
910 if (pRect->y < 0) {
911 pRect->h += pRect->y;
912 pRect->y = 0;
913 } else {
914 if (pRect->y >= pSurface->h - pRect->h) {
915 pRect->h = pSurface->h - pRect->y;
919 start = pixel = (Uint32 *) pSurface->pixels +
920 (pRect->y * pSurface->pitch) + pRect->x / 2;
922 if (A == 16) { /* A == 128 >> 3 */
923 S = S | S << 16;
924 for (y = 0; y < pRect->h; y++) {
925 end = 0;
927 if (pRect->w & 0x1) {
928 D = *pixel;
929 *pixel++ = BLEND16_50(D, (S & 0xFFFF), MASK555);
930 end++;
933 for (; end < pRect->w; end += 2) {
934 D = *(Uint32 *) pixel;
935 *(Uint32 *) pixel = BLEND2x16_50(D, S, MASK555);
936 pixel += 2;
939 pixel = start + pSurface->pitch;
940 start = pixel;
942 } else {
944 S = (S | S << 16) & 0x03e07c1f;
945 y = pRect->h;
946 end = pRect->w;
948 while( y--) {
949 DUFFS_LOOP8(
951 D = *pixel;
952 D = (D | D << 16) & 0x03e07c1f;
953 D += (S - D) * A >> 5;
954 D &= 0x03e07c1f;
955 *pixel++ = (D | (D >> 16)) & 0xFFFF;
956 }, end);
958 pixel = start + pSurface->pitch;
959 start = pixel;
960 } /* while */
964 unlock_surf(pSurface);
965 return 0;
968 /**************************************************************************
969 Fill rectangle for 32bit "8888" format surface
970 **************************************************************************/
971 static int __FillRectAlpha8888_32bit(SDL_Surface *pSurface, SDL_Rect *pRect,
972 SDL_Color *pColor)
974 register Uint32 A = pColor->a;
975 register Uint32 dSIMD1, dSIMD2;
976 register Uint32 sSIMD1, sSIMD2 = SDL_MapRGB(pSurface->format,
977 pColor->r, pColor->g,
978 pColor->b);
979 Uint32 y, end, A_Dst, A_Mask = pSurface->format->Amask;
980 Uint32 *start, *pixel;
982 sSIMD1 = sSIMD2 & 0x00FF00FF;
984 lock_surf(pSurface);
986 if (pRect == NULL) {
987 end = pSurface->w * pSurface->h;
988 pixel = (Uint32 *) pSurface->pixels;
989 if (A == 128) { /* 50% A */
990 DUFFS_LOOP8(
992 dSIMD2 = *pixel;
993 A_Dst = dSIMD2 & A_Mask;
994 *pixel++ = ((((sSIMD2 & 0x00fefefe) + (dSIMD2 & 0x00fefefe)) >> 1)
995 + (sSIMD2 & dSIMD2 & 0x00010101)) | A_Dst;
996 }, end);
997 } else {
998 sSIMD2 &= 0xFF00;
999 sSIMD2 = sSIMD2 >> 8 | sSIMD2 << 8;
1000 DUFFS_LOOP_DOUBLE2(
1002 dSIMD2 = *pixel;
1003 A_Dst = dSIMD2 & A_Mask;
1004 dSIMD1 = dSIMD2 & 0x00FF00FF;
1005 dSIMD1 += (sSIMD1 - dSIMD1) * A >> 8;
1006 dSIMD1 &= 0x00FF00FF;
1007 dSIMD2 &= 0xFF00;
1008 dSIMD2 += (((sSIMD2 << 8) & 0xFF00) - dSIMD2) * A >> 8;
1009 dSIMD2 &= 0xFF00;
1010 *pixel++ = dSIMD1 | dSIMD2 | A_Dst;
1012 dSIMD1 = *pixel;
1013 A_Dst = dSIMD1 & A_Mask;
1014 dSIMD1 &= 0x00FF00FF;
1015 dSIMD1 += (sSIMD1 - dSIMD1) * A >> 8;
1016 dSIMD1 &= 0x00FF00FF;
1018 dSIMD2 = ((*pixel & 0xFF00) >> 8)| ((pixel[1] & 0xFF00) << 8);
1019 dSIMD2 += (sSIMD2 - dSIMD2) * A >> 8;
1020 dSIMD2 &= 0x00FF00FF;
1022 *pixel++ = dSIMD1 | ((dSIMD2 << 8) & 0xFF00) | A_Dst;
1024 dSIMD1 = *pixel;
1025 A_Dst = dSIMD1 & A_Mask;
1026 dSIMD1 &= 0x00FF00FF;
1027 dSIMD1 += (sSIMD1 - dSIMD1) * A >> 8;
1028 dSIMD1 &= 0x00FF00FF;
1030 *pixel++ = dSIMD1 | ((dSIMD2 >> 8) & 0xFF00) | A_Dst;
1031 }, end);
1033 } else {
1034 /* correct pRect size */
1035 if (pRect->x < 0) {
1036 pRect->w += pRect->x;
1037 pRect->x = 0;
1038 } else {
1039 if (pRect->x >= pSurface->w - pRect->w) {
1040 pRect->w = pSurface->w - pRect->x;
1044 if (pRect->y < 0) {
1045 pRect->h += pRect->y;
1046 pRect->y = 0;
1047 } else {
1048 if (pRect->y >= pSurface->h - pRect->h) {
1049 pRect->h = pSurface->h - pRect->y;
1053 start = pixel = (Uint32 *) pSurface->pixels +
1054 (pRect->y * (pSurface->pitch >> 2)) + pRect->x;
1056 if (A == 128) { /* 50% A */
1057 y = pRect->h;
1058 end = pRect->w;
1059 while (y--) {
1060 DUFFS_LOOP4(
1062 dSIMD2 = *pixel;
1063 A_Dst = dSIMD2 & A_Mask;
1064 *pixel++ = ((((sSIMD2 & 0x00fefefe) + (dSIMD2 & 0x00fefefe)) >> 1)
1065 + (sSIMD2 & dSIMD2 & 0x00010101)) | A_Dst;
1066 }, end);
1067 pixel = start + (pSurface->pitch >> 2);
1068 start = pixel;
1070 } else {
1071 y = pRect->h;
1072 end = pRect->w;
1074 sSIMD2 &= 0xFF00;
1075 sSIMD2 = sSIMD2 >> 8 | sSIMD2 << 8;
1077 while (y--) {
1078 DUFFS_LOOP_DOUBLE2(
1080 dSIMD2 = *pixel;
1081 A_Dst = dSIMD2 & A_Mask;
1082 dSIMD1 = dSIMD2 & 0x00FF00FF;
1083 dSIMD1 += (sSIMD1 - dSIMD1) * A >> 8;
1084 dSIMD1 &= 0x00FF00FF;
1085 dSIMD2 &= 0xFF00;
1086 dSIMD2 += (((sSIMD2 << 8) & 0xFF00) - dSIMD2) * A >> 8;
1087 dSIMD2 &= 0xFF00;
1088 *pixel++ = dSIMD1 | dSIMD2 | A_Dst;
1090 dSIMD1 = *pixel;
1091 A_Dst = dSIMD1 & A_Mask;
1092 dSIMD1 &= 0x00FF00FF;
1093 dSIMD1 += (sSIMD1 - dSIMD1) * A >> 8;
1094 dSIMD1 &= 0x00FF00FF;
1096 dSIMD2 = ((*pixel & 0xFF00) >> 8)| ((pixel[1] & 0xFF00) << 8);
1097 dSIMD2 += (sSIMD2 - dSIMD2) * A >> 8;
1098 dSIMD2 &= 0x00FF00FF;
1100 *pixel++ = dSIMD1 | ((dSIMD2 << 8) & 0xFF00) | A_Dst;
1102 dSIMD1 = *pixel;
1103 A_Dst = dSIMD1 & A_Mask;
1104 dSIMD1 &= 0x00FF00FF;
1105 dSIMD1 += (sSIMD1 - dSIMD1) * A >> 8;
1106 dSIMD1 &= 0x00FF00FF;
1108 *pixel++ = dSIMD1 | ((dSIMD2 >> 8) & 0xFF00) | A_Dst;
1109 }, end);
1111 pixel = start + (pSurface->pitch >> 2);
1112 start = pixel;
1113 } /* while */
1117 unlock_surf(pSurface);
1118 return 0;
1121 /**************************************************************************
1122 Fill rectangle for 32bit "888" format surface
1123 **************************************************************************/
1124 static int __FillRectAlpha888_32bit(SDL_Surface *pSurface, SDL_Rect *pRect,
1125 SDL_Color *pColor)
1127 register Uint32 A = pColor->a;
1128 register Uint32 dSIMD1, dSIMD2;
1129 register Uint32 sSIMD1, sSIMD2 = SDL_MapRGB(pSurface->format,
1130 pColor->r, pColor->g,
1131 pColor->b);
1132 Uint32 y, end;
1133 Uint32 *start, *pixel;
1135 sSIMD1 = sSIMD2 & 0x00FF00FF;
1137 lock_surf(pSurface);
1139 if (pRect == NULL) {
1140 end = pSurface->w * pSurface->h;
1141 pixel = (Uint32 *) pSurface->pixels;
1142 if (A == 128) { /* 50% A */
1143 for (y = 0; y < end; y++) {
1144 dSIMD2 = *pixel;
1145 *pixel++ = ((((sSIMD2 & 0x00fefefe) + (dSIMD2 & 0x00fefefe)) >> 1)
1146 + (sSIMD2 & dSIMD2 & 0x00010101)) | 0xFF000000;
1148 } else {
1149 sSIMD2 &= 0xFF00;
1150 sSIMD2 = sSIMD2 >> 8 | sSIMD2 << 8;
1151 DUFFS_LOOP_DOUBLE2(
1153 dSIMD2 = *pixel;
1154 dSIMD1 = dSIMD2 & 0x00FF00FF;
1155 dSIMD1 += (sSIMD1 - dSIMD1) * A >> 8;
1156 dSIMD1 &= 0x00FF00FF;
1157 dSIMD2 &= 0xFF00;
1158 dSIMD2 += (((sSIMD2 << 8) & 0xFF00) - dSIMD2) * A >> 8;
1159 dSIMD2 &= 0xFF00;
1160 *pixel++ = dSIMD1 | dSIMD2 | 0xFF000000;
1162 dSIMD1 = *pixel & 0x00FF00FF;
1163 dSIMD1 += (sSIMD1 - dSIMD1) * A >> 8;
1164 dSIMD1 &= 0x00FF00FF;
1166 dSIMD2 = ((*pixel & 0xFF00) >> 8)| ((pixel[1] & 0xFF00) << 8);
1167 dSIMD2 += (sSIMD2 - dSIMD2) * A >> 8;
1168 dSIMD2 &= 0x00FF00FF;
1170 *pixel++ = dSIMD1 | ((dSIMD2 << 8) & 0xFF00) | 0xFF000000;
1172 dSIMD1 = *pixel & 0x00FF00FF;
1173 dSIMD1 += (sSIMD1 - dSIMD1) * A >> 8;
1174 dSIMD1 &= 0x00FF00FF;
1176 *pixel++ = dSIMD1 | ((dSIMD2 >> 8) & 0xFF00) | 0xFF000000;
1177 }, end);
1179 } else {
1180 /* correct pRect size */
1181 if (pRect->x < 0) {
1182 pRect->w += pRect->x;
1183 pRect->x = 0;
1184 } else {
1185 if (pRect->x >= pSurface->w - pRect->w) {
1186 pRect->w = pSurface->w - pRect->x;
1190 if (pRect->y < 0) {
1191 pRect->h += pRect->y;
1192 pRect->y = 0;
1193 } else {
1194 if (pRect->y >= pSurface->h - pRect->h) {
1195 pRect->h = pSurface->h - pRect->y;
1199 start = pixel = (Uint32 *) pSurface->pixels +
1200 (pRect->y * (pSurface->pitch >> 2)) + pRect->x;
1202 if (A == 128) { /* 50% A */
1204 for (y = 0; y < pRect->h; y++) {
1206 for (end = 0; end < pRect->w; end++) {
1207 dSIMD2 = *pixel;
1208 *pixel++ = ((((sSIMD2 & 0x00fefefe) + (dSIMD2 & 0x00fefefe)) >> 1)
1209 + (sSIMD2 & dSIMD2 & 0x00010101)) | 0xFF000000;
1212 pixel = start + (pSurface->pitch >> 2);
1213 start = pixel;
1215 } else {
1216 y = pRect->h;
1217 end = pRect->w;
1219 sSIMD2 &= 0xFF00;
1220 sSIMD2 = sSIMD2 >> 8 | sSIMD2 << 8;
1222 while (y--) {
1223 DUFFS_LOOP_DOUBLE2(
1225 dSIMD2 = *pixel;
1226 dSIMD1 = dSIMD2 & 0x00FF00FF;
1227 dSIMD1 += (sSIMD1 - dSIMD1) * A >> 8;
1228 dSIMD1 &= 0x00FF00FF;
1229 dSIMD2 &= 0xFF00;
1230 dSIMD2 += (((sSIMD2 << 8) & 0xFF00) - dSIMD2) * A >> 8;
1231 dSIMD2 &= 0xFF00;
1232 *pixel++ = dSIMD1 | dSIMD2 | 0xFF000000;
1234 dSIMD1 = *pixel & 0x00FF00FF;
1235 dSIMD1 += (sSIMD1 - dSIMD1) * A >> 8;
1236 dSIMD1 &= 0x00FF00FF;
1238 dSIMD2 = ((*pixel & 0xFF00) >> 8)| ((pixel[1] & 0xFF00) << 8);
1239 dSIMD2 += (sSIMD2 - dSIMD2) * A >> 8;
1240 dSIMD2 &= 0x00FF00FF;
1242 *pixel++ = dSIMD1 | ((dSIMD2 << 8) & 0xFF00) | 0xFF000000;
1244 dSIMD1 = *pixel & 0x00FF00FF;
1245 dSIMD1 += (sSIMD1 - dSIMD1) * A >> 8;
1246 dSIMD1 &= 0x00FF00FF;
1248 *pixel++ = dSIMD1 | ((dSIMD2 >> 8) & 0xFF00) | 0xFF000000;
1249 }, end);
1251 pixel = start + (pSurface->pitch >> 2);
1252 start = pixel;
1254 } /* while */
1258 unlock_surf(pSurface);
1259 return 0;
1262 /**************************************************************************
1263 Fill rectangle for 24bit "888" format surface
1264 **************************************************************************/
1265 static int __FillRectAlpha888_24bit(SDL_Surface *pSurface, SDL_Rect *pRect,
1266 SDL_Color *pColor)
1268 Uint32 y, end;
1269 Uint8 *start, *pixel;
1270 register Uint32 P, D, S1, S2 = SDL_MapRGB(pSurface->format,
1271 pColor->r, pColor->g,
1272 pColor->b);
1273 register Uint32 A = pColor->a;
1275 S1 = S2 & 0x00FF00FF;
1277 S2 &= 0xFF00;
1279 lock_surf(pSurface);
1281 if (pRect == NULL) {
1282 end = pSurface->w * pSurface->h;
1283 pixel = (Uint8 *) pSurface->pixels;
1285 for (y = 0; y < end; y++) {
1286 D = (pixel[0] << 16) + (pixel[1] << 8) + pixel[2];
1288 P = D & 0x00FF00FF;
1289 P += (S1 - P) * A >> 8;
1290 P &= 0x00ff00ff;
1292 D = (D & 0xFF00);
1293 D += (S2 - D) * A >> 8;
1294 D &= 0xFF00;
1296 P = P | D;
1298 /* Fix me to little - big EDIAN */
1300 pixel[0] = P & 0xff;
1301 pixel[1] = (P >> 8) & 0xff;
1302 pixel[2] = (P >> 16) & 0xff;
1304 pixel += 3;
1307 } else {
1308 /* correct pRect size */
1309 if (pRect->x < 0) {
1310 pRect->w += pRect->x;
1311 pRect->x = 0;
1312 } else {
1313 if (pRect->x >= pSurface->w - pRect->w) {
1314 pRect->w = pSurface->w - pRect->x;
1318 if (pRect->y < 0) {
1319 pRect->h += pRect->y;
1320 pRect->y = 0;
1321 } else {
1322 if (pRect->y >= pSurface->h - pRect->h) {
1323 pRect->h = pSurface->h - pRect->y;
1327 end = pRect->w * pRect->h;
1328 start = pixel = (Uint8 *) pSurface->pixels +
1329 (pRect->y * pSurface->pitch) + pRect->x * 3;
1331 y = 0;
1332 while (y != pRect->h) {
1333 D = (pixel[0] << 16) + (pixel[1] << 8) + pixel[2];
1335 P = D & 0x00FF00FF;
1336 P += (S1 - P) * A >> 8;
1337 P &= 0x00ff00ff;
1339 D = (D & 0xFF00);
1340 D += (S2 - D) * A >> 8;
1341 D &= 0xFF00;
1343 P = P | D;
1345 /* Fix me to little - big EDIAN */
1347 pixel[0] = P & 0xff;
1348 pixel[1] = (P >> 8) & 0xff;
1349 pixel[2] = (P >> 16) & 0xff;
1351 if ((pixel - start) == (pRect->w * 3)) {
1352 pixel = start + pSurface->pitch;
1353 start = pixel;
1354 y++;
1355 } else {
1356 pixel += 3;
1361 unlock_surf(pSurface);
1363 return 0;
1366 /**************************************************************************
1367 Fill rectangle with color with alpha channel.
1368 **************************************************************************/
1369 int fill_rect_alpha(SDL_Surface *pSurface, SDL_Rect *pRect,
1370 SDL_Color *pColor)
1372 if (pRect && (pRect->x < - pRect->w || pRect->x >= pSurface->w
1373 || pRect->y < - pRect->h || pRect->y >= pSurface->h)) {
1374 return -2;
1377 if (pColor->a == 255) {
1378 return SDL_FillRect(pSurface, pRect,
1379 SDL_MapRGB(pSurface->format, pColor->r, pColor->g, pColor->b));
1382 if (!pColor->a) {
1383 return -3;
1386 switch (pSurface->format->BytesPerPixel) {
1387 case 1:
1388 /* PORT ME */
1389 return -1;
1391 case 2:
1392 if (pSurface->format->Gmask == 0x7E0) {
1393 return __FillRectAlpha565(pSurface, pRect, pColor);
1394 } else {
1395 if (pSurface->format->Gmask == 0x3E0) {
1396 return __FillRectAlpha555(pSurface, pRect, pColor);
1397 } else {
1398 return -1;
1401 break;
1403 case 3:
1404 return __FillRectAlpha888_24bit(pSurface, pRect, pColor);
1406 case 4:
1407 if (pSurface->format->Amask) {
1408 return __FillRectAlpha8888_32bit(pSurface, pRect, pColor);
1409 } else {
1410 return __FillRectAlpha888_32bit(pSurface, pRect, pColor);
1414 return -1;
1417 /**************************************************************************
1418 Make rectangle region sane. Return TRUE if result is sane.
1419 **************************************************************************/
1420 bool correct_rect_region(SDL_Rect *pRect)
1422 int ww = pRect->w, hh = pRect->h;
1424 if (pRect->x < 0) {
1425 ww += pRect->x;
1426 pRect->x = 0;
1429 if (pRect->y < 0) {
1430 hh += pRect->y;
1431 pRect->y = 0;
1434 if (pRect->x + ww > main_window_width()) {
1435 ww = main_window_width() - pRect->x;
1438 if (pRect->y + hh > main_window_height()) {
1439 hh = main_window_height() - pRect->y;
1442 /* End Correction */
1444 if (ww <= 0 || hh <= 0) {
1445 return FALSE; /* suprise :) */
1446 } else {
1447 pRect->w = ww;
1448 pRect->h = hh;
1451 return TRUE;
1454 /**************************************************************************
1455 Return whether coordinates are in rectangle.
1456 **************************************************************************/
1457 bool is_in_rect_area(int x, int y, SDL_Rect rect)
1459 return ((x >= rect.x) && (x < rect.x + rect.w)
1460 && (y >= rect.y) && (y < rect.y + rect.h));
1463 /**************************************************************************
1464 Most black color is coded like {0,0,0,255} but in sdl if alpha is turned
1465 off and colorkey is set to 0 this black color is transparent.
1466 To fix this we change all black {0, 0, 0, 255} to newblack {4, 4, 4, 255}
1467 (first collor != 0 in 16 bit coding).
1468 **************************************************************************/
1469 bool correct_black(SDL_Surface *pSrc)
1471 #if 0
1472 bool ret = 0;
1473 register int x;
1475 if (pSrc->format->BitsPerPixel == 32 && pSrc->format->Amask) {
1476 register Uint32 alpha, *pPixels = (Uint32 *) pSrc->pixels;
1477 Uint32 Amask = pSrc->format->Amask;
1478 Uint32 black = SDL_MapRGBA(pSrc->format, 0, 0, 0, 255);
1479 Uint32 new_black = SDL_MapRGBA(pSrc->format, 4, 4, 4, 255);
1480 int end = pSrc->w * pSrc->h;
1482 /* for 32 bit color coding */
1484 lock_surf(pSrc);
1486 for (x = 0; x < end; x++, pPixels++) {
1487 if (*pPixels == black) {
1488 *pPixels = new_black;
1489 } else {
1490 if (!ret) {
1491 alpha = *pPixels & Amask;
1492 if (alpha && (alpha != Amask)) {
1493 ret = 1;
1499 unlock_surf(pSrc);
1500 } else {
1501 if (pSrc->format->BitsPerPixel == 8 && pSrc->format->palette) {
1502 for(x = 0; x < pSrc->format->palette->ncolors; x++) {
1503 if (x != pSrc->format->colorkey &&
1504 pSrc->format->palette->colors[x].r < 4 &&
1505 pSrc->format->palette->colors[x].g < 4 &&
1506 pSrc->format->palette->colors[x].b < 4) {
1507 pSrc->format->palette->colors[x].r = 4;
1508 pSrc->format->palette->colors[x].g = 4;
1509 pSrc->format->palette->colors[x].b = 4;
1515 return ret;
1516 #endif /* 0 */
1518 return TRUE;
1521 /* ===================================================================== */
1523 /**************************************************************************
1524 Get visible rectangle from surface.
1525 **************************************************************************/
1526 SDL_Rect get_smaller_surface_rect(SDL_Surface *pSurface)
1528 SDL_Rect src;
1529 int w, h, x, y;
1530 Uint16 minX, maxX, minY, maxY;
1531 Uint32 colorkey;
1533 fc_assert(pSurface != NULL);
1535 minX = pSurface->w;
1536 maxX = 0;
1537 minY = pSurface->h;
1538 maxY = 0;
1539 SDL_GetColorKey(pSurface, &colorkey);
1541 lock_surf(pSurface);
1543 switch(pSurface->format->BytesPerPixel) {
1544 case 1:
1546 Uint8 *pixel = (Uint8 *)pSurface->pixels;
1547 Uint8 *start = pixel;
1548 x = 0;
1549 y = 0;
1550 w = pSurface->w;
1551 h = pSurface->h;
1552 while (h--) {
1553 do {
1554 if (*pixel != colorkey) {
1555 if (minY > y) {
1556 minY = y;
1559 if (minX > x) {
1560 minX = x;
1562 break;
1564 pixel++;
1565 x++;
1566 } while( --w > 0 );
1567 w = pSurface->w;
1568 x = 0;
1569 y++;
1570 pixel = start + pSurface->pitch;
1571 start = pixel;
1574 w = pSurface->w;
1575 h = pSurface->h;
1576 x = w - 1;
1577 y = h - 1;
1578 pixel = (Uint8 *)((Uint8 *)pSurface->pixels + (y * pSurface->pitch) + x);
1579 start = pixel;
1580 while (h--) {
1581 do {
1582 if (*pixel != colorkey) {
1583 if (maxY < y) {
1584 maxY = y;
1587 if (maxX < x) {
1588 maxX = x;
1590 break;
1592 pixel--;
1593 x--;
1594 } while( --w > 0 );
1595 w = pSurface->w;
1596 x = w - 1;
1597 y--;
1598 pixel = start - pSurface->pitch;
1599 start = pixel;
1602 break;
1603 case 2:
1605 Uint16 *pixel = (Uint16 *)pSurface->pixels;
1606 Uint16 *start = pixel;
1608 x = 0;
1609 y = 0;
1610 w = pSurface->w;
1611 h = pSurface->h;
1612 while (h--) {
1613 do {
1614 if (*pixel != colorkey) {
1615 if (minY > y) {
1616 minY = y;
1619 if (minX > x) {
1620 minX = x;
1622 break;
1624 pixel++;
1625 x++;
1626 } while( --w > 0 );
1627 w = pSurface->w;
1628 x = 0;
1629 y++;
1630 pixel = start + pSurface->pitch / 2;
1631 start = pixel;
1634 w = pSurface->w;
1635 h = pSurface->h;
1636 x = w - 1;
1637 y = h - 1;
1638 pixel = ((Uint16 *)pSurface->pixels + (y * pSurface->pitch / 2) + x);
1639 start = pixel;
1640 while (h--) {
1641 do {
1642 if (*pixel != colorkey) {
1643 if (maxY < y) {
1644 maxY = y;
1647 if (maxX < x) {
1648 maxX = x;
1650 break;
1652 pixel--;
1653 x--;
1654 } while( --w > 0 );
1655 w = pSurface->w;
1656 x = w - 1;
1657 y--;
1658 pixel = start - pSurface->pitch / 2;
1659 start = pixel;
1662 break;
1663 case 3:
1665 Uint8 *pixel = (Uint8 *)pSurface->pixels;
1666 Uint8 *start = pixel;
1667 Uint32 color;
1669 x = 0;
1670 y = 0;
1671 w = pSurface->w;
1672 h = pSurface->h;
1673 while (h--) {
1674 do {
1675 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1676 color = (pixel[0] << 16 | pixel[1] << 8 | pixel[2]);
1677 } else {
1678 color = (pixel[0] | pixel[1] << 8 | pixel[2] << 16);
1680 if (color != colorkey) {
1681 if (minY > y) {
1682 minY = y;
1685 if (minX > x) {
1686 minX = x;
1688 break;
1690 pixel += 3;
1691 x++;
1692 } while( --w > 0 );
1693 w = pSurface->w;
1694 x = 0;
1695 y++;
1696 pixel = start + pSurface->pitch / 3;
1697 start = pixel;
1700 w = pSurface->w;
1701 h = pSurface->h;
1702 x = w - 1;
1703 y = h - 1;
1704 pixel = (Uint8 *)((Uint8 *)pSurface->pixels + (y * pSurface->pitch) + x * 3);
1705 start = pixel;
1706 while (h--) {
1707 do {
1708 if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1709 color = (pixel[0] << 16 | pixel[1] << 8 | pixel[2]);
1710 } else {
1711 color = (pixel[0] | pixel[1] << 8 | pixel[2] << 16);
1713 if (color != colorkey) {
1714 if (maxY < y) {
1715 maxY = y;
1718 if (maxX < x) {
1719 maxX = x;
1721 break;
1723 pixel -= 3;
1724 x--;
1725 } while( --w > 0 );
1726 w = pSurface->w;
1727 x = w - 1;
1728 y--;
1729 pixel = start - pSurface->pitch / 3;
1730 start = pixel;
1733 break;
1734 case 4:
1736 Uint32 *pixel = (Uint32 *)pSurface->pixels;
1737 Uint32 *start = pixel;
1739 x = 0;
1740 y = 0;
1741 w = pSurface->w;
1742 h = pSurface->h;
1743 while(h--) {
1744 do {
1745 if (*pixel != colorkey) {
1746 if (minY > y) {
1747 minY = y;
1750 if (minX > x) {
1751 minX = x;
1753 break;
1755 pixel++;
1756 x++;
1757 } while( --w > 0 );
1758 w = pSurface->w;
1759 x = 0;
1760 y++;
1761 pixel = start + pSurface->pitch / 4;
1762 start = pixel;
1765 w = pSurface->w;
1766 h = pSurface->h;
1767 x = w - 1;
1768 y = h - 1;
1769 pixel = ((Uint32 *)pSurface->pixels + (y * pSurface->pitch / 4) + x);
1770 start = pixel;
1771 while (h--) {
1772 do {
1773 if (*pixel != colorkey) {
1774 if (maxY < y) {
1775 maxY = y;
1778 if (maxX < x) {
1779 maxX = x;
1781 break;
1783 pixel--;
1784 x--;
1785 } while( --w > 0 );
1786 w = pSurface->w;
1787 x = w - 1;
1788 y--;
1789 pixel = start - pSurface->pitch / 4;
1790 start = pixel;
1793 break;
1796 unlock_surf(pSurface);
1797 src.x = minX;
1798 src.y = minY;
1799 src.w = maxX - minX + 1;
1800 src.h = maxY - minY + 1;
1802 return src;
1805 /**************************************************************************
1806 Create new surface that is just visible part of source surface.
1807 **************************************************************************/
1808 SDL_Surface *crop_visible_part_from_surface(SDL_Surface *pSrc)
1810 SDL_Rect src = get_smaller_surface_rect(pSrc);
1812 return crop_rect_from_surface(pSrc, &src);
1815 /**************************************************************************
1816 Scale surface.
1817 **************************************************************************/
1818 SDL_Surface *ResizeSurface(const SDL_Surface *pSrc, Uint16 new_width,
1819 Uint16 new_height, int smooth)
1821 if (pSrc == NULL) {
1822 return NULL;
1825 return zoomSurface((SDL_Surface*)pSrc,
1826 (double)new_width / pSrc->w,
1827 (double)new_height / pSrc->h,
1828 smooth);
1831 /**************************************************************************
1832 Resize a surface to fit into a box with the dimensions 'new_width' and a
1833 'new_height'. If 'scale_up' is FALSE, a surface that already fits into
1834 the box will not be scaled up to the boundaries of the box.
1835 If 'absolute_dimensions' is TRUE, the function returns a surface with the
1836 dimensions of the box and the scaled/original surface centered in it.
1837 **************************************************************************/
1838 SDL_Surface *ResizeSurfaceBox(const SDL_Surface *pSrc,
1839 Uint16 new_width, Uint16 new_height, int smooth,
1840 bool scale_up, bool absolute_dimensions)
1842 SDL_Surface *tmpSurface, *result;
1844 if (pSrc == NULL) {
1845 return NULL;
1848 if (!((scale_up == FALSE) && ((new_width >= pSrc->w) && (new_height >= pSrc->h)))) {
1849 if ((new_width - pSrc->w) <= (new_height - pSrc->h)) {
1850 /* horizontal limit */
1851 tmpSurface = zoomSurface((SDL_Surface*)pSrc,
1852 (double)new_width / pSrc->w,
1853 (double)new_width / pSrc->w,
1854 smooth);
1855 } else {
1856 /* vertical limit */
1857 tmpSurface = zoomSurface((SDL_Surface*)pSrc,
1858 (double)new_height / pSrc->h,
1859 (double)new_height / pSrc->h,
1860 smooth);
1862 } else {
1863 tmpSurface = zoomSurface((SDL_Surface*)pSrc,
1864 1.0,
1865 1.0,
1866 smooth);
1869 if (absolute_dimensions) {
1870 SDL_Rect area = {
1871 (new_width - tmpSurface->w) / 2,
1872 (new_height - tmpSurface->h) / 2,
1873 0, 0
1876 result = create_surf(new_width, new_height, SDL_SWSURFACE);
1877 alphablit(tmpSurface, NULL, result, &area, 255);
1878 FREESURFACE(tmpSurface);
1879 } else {
1880 result = tmpSurface;
1883 return result;
1886 /**************************************************************************
1887 Return copy of the surface
1888 **************************************************************************/
1889 SDL_Surface *copy_surface(SDL_Surface *src)
1891 SDL_Surface *dst;
1893 dst = SDL_CreateRGBSurface(0, src->w, src->h, src->format->BitsPerPixel,
1894 src->format->Rmask, src->format->Gmask,
1895 src->format->Bmask, src->format->Amask);
1897 SDL_BlitSurface(src, NULL, dst, NULL);
1899 return dst;
1902 /* ============ Freeciv game graphics function =========== */
1904 /**************************************************************************
1905 Return whether the client supports given view type
1906 **************************************************************************/
1907 bool is_view_supported(enum ts_type type)
1909 switch (type) {
1910 case TS_ISOMETRIC:
1911 case TS_OVERHEAD:
1912 return TRUE;
1915 return FALSE;
1918 /**************************************************************************
1919 Load intro sprites. Not used in SDL-client.
1920 **************************************************************************/
1921 void load_intro_gfx(void)
1923 /* nothing */
1926 /**************************************************************************
1927 Frees the introductory sprites.
1928 **************************************************************************/
1929 void free_intro_radar_sprites(void)
1931 /* nothing */
1934 /**************************************************************************
1935 Create colored frame
1936 **************************************************************************/
1937 void create_frame(SDL_Surface *dest, Sint16 left, Sint16 top,
1938 Sint16 width, Sint16 height,
1939 SDL_Color *pcolor)
1941 struct color gsdl2_color = { .color = pcolor };
1942 struct sprite *vertical = create_sprite(1, height, &gsdl2_color);
1943 struct sprite *horizontal = create_sprite(width, 1, &gsdl2_color);
1944 SDL_Rect tmp,dst = { left, top, 0, 0 };
1946 tmp = dst;
1947 alphablit(vertical->psurface, NULL, dest, &tmp, 255);
1949 dst.x += width - 1;
1950 tmp = dst;
1951 alphablit(vertical->psurface, NULL, dest, &tmp, 255);
1953 dst.x = left;
1954 tmp = dst;
1955 alphablit(horizontal->psurface, NULL, dest, &tmp, 255);
1957 dst.y += height - 1;
1958 tmp = dst;
1959 alphablit(horizontal->psurface, NULL, dest, &tmp, 255);
1961 free_sprite(horizontal);
1962 free_sprite(vertical);
1965 /**************************************************************************
1966 Create single colored line
1967 **************************************************************************/
1968 void create_line(SDL_Surface *dest, Sint16 x0, Sint16 y0, Sint16 x1, Sint16 y1,
1969 SDL_Color *pcolor)
1971 int xl = x0 < x1 ? x0 : x1;
1972 int xr = x0 < x1 ? x1 : x0;
1973 int yt = y0 < y1 ? y0 : y1;
1974 int yb = y0 < y1 ? y1 : y0;
1975 int w = (xr - xl) + 1;
1976 int h = (yb - yt) + 1;
1977 struct sprite *spr;
1978 SDL_Rect dst = { xl, yt, w, h };
1979 SDL_Color *pcol;
1980 struct color gsdl2_color;
1981 int l = MAX((xr - xl) + 1, (yb - yt) + 1);
1982 int i;
1984 pcol = fc_malloc(sizeof(pcol));
1985 pcol->r = pcolor->r;
1986 pcol->g = pcolor->g;
1987 pcol->b = pcolor->b;
1988 pcol->a = 0; /* Fill with transparency */
1990 gsdl2_color.color = pcol;
1991 spr = create_sprite(w, h, &gsdl2_color);
1993 lock_surf(spr->psurface);
1995 /* Set off transparency from pixels belonging to the line */
1996 if ((x0 <= x1 && y0 <= y1)
1997 || (x1 <= x0 && y1 <= y0)) {
1998 for (i = 0; i < l; i++) {
1999 int cx = (xr - xl) * i / l;
2000 int cy = (yb - yt) * i / l;
2002 *((Uint32 *)spr->psurface->pixels + spr->psurface->w * cy + cx)
2003 |= (pcolor->a << spr->psurface->format->Ashift);
2005 } else {
2006 for (i = 0; i < l; i++) {
2007 int cx = (xr - xl) * i / l;
2008 int cy = yb - (yb - yt) * i / l;
2010 *((Uint32 *)spr->psurface->pixels + spr->psurface->w * cy + cx)
2011 |= (pcolor->a << spr->psurface->format->Ashift);
2015 unlock_surf(spr->psurface);
2017 alphablit(spr->psurface, NULL, dest, &dst, 255);
2019 free_sprite(spr);
2020 free(pcol);