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.
7 
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 ***********************************************************************/
13 
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 ***********************************************************************/
23 
24 #ifdef HAVE_CONFIG_H
25 #include <fc_config.h>
26 #endif
27 
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 */
38 
39 /* utility */
40 #include "fcintl.h"
41 #include "log.h"
42 
43 /* client */
44 #include "tilespec.h"
45 
46 /* gui-sdl2 */
47 #include "colors.h"
48 #include "gui_tilespec.h"
49 #include "mapview.h"
50 #include "themebackgrounds.h"
51 #include "themespec.h"
52 
53 #include "graphics.h"
54 
55 /* ------------------------------ */
56 
57 struct main Main;
58 
59 static SDL_Surface *main_surface;
60 
61 static bool render_dirty = TRUE;
62 
63 /**************************************************************************
64   Allocate new gui_layer.
65 **************************************************************************/
gui_layer_new(int x,int y,SDL_Surface * surface)66 struct gui_layer *gui_layer_new(int x, int y, SDL_Surface *surface)
67 {
68   struct gui_layer *result;
69 
70   result = fc_calloc(1, sizeof(struct gui_layer));
71 
72   result->dest_rect = (SDL_Rect){x, y, 0, 0};
73   result->surface = surface;
74 
75   return result;
76 }
77 
78 /**************************************************************************
79   Free resources associated with gui_layer.
80 **************************************************************************/
gui_layer_destroy(struct gui_layer ** gui_layer)81 void gui_layer_destroy(struct gui_layer **gui_layer)
82 {
83   FREESURFACE((*gui_layer)->surface);
84   FC_FREE(*gui_layer);
85 }
86 
87 /**************************************************************************
88   Get surface gui_layer.
89 **************************************************************************/
get_gui_layer(SDL_Surface * surface)90 struct gui_layer *get_gui_layer(SDL_Surface *surface)
91 {
92   int i = 0;
93 
94   while ((i < Main.guis_count) && Main.guis[i]) {
95     if (Main.guis[i]->surface == surface) {
96       return Main.guis[i];
97     }
98     i++;
99   }
100 
101   return NULL;
102 }
103 
104 /**************************************************************************
105   Buffer allocation function.
106   This function is call by "create_window(...)" function and allocate
107   buffer layer for this function.
108 
109   Pointer for this buffer is put in buffer array on last position that
110   flush functions will draw this layer last.
111 **************************************************************************/
add_gui_layer(int width,int height)112 struct gui_layer *add_gui_layer(int width, int height)
113 {
114   struct gui_layer *gui_layer = NULL;
115   SDL_Surface *pBuffer;
116 
117   pBuffer = create_surf(width, height, SDL_SWSURFACE);
118   gui_layer = gui_layer_new(0, 0, pBuffer);
119 
120   /* add to buffers array */
121   if (Main.guis) {
122     int i;
123 
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;
129       }
130     }
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;
138   }
139 
140   return gui_layer;
141 }
142 
143 /**************************************************************************
144   Free buffer layer ( call by popdown_window_group_dialog(...) funct )
145   Funct. free buffer layer and cleare buffer array entry.
146 **************************************************************************/
remove_gui_layer(struct gui_layer * gui_layer)147 void remove_gui_layer(struct gui_layer *gui_layer)
148 {
149   int i;
150 
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;
160       }
161     }
162   }
163 
164   if (Main.guis[Main.guis_count - 1]) {
165     gui_layer_destroy(&Main.guis[Main.guis_count - 1]);
166   }
167 }
168 
169 /**********************************************************************//**
170   Translate dest_rect from global screen to gui_layer's coordinates.
171 **************************************************************************/
screen_rect_to_layer_rect(struct gui_layer * gui_layer,SDL_Rect * dest_rect)172 void screen_rect_to_layer_rect(struct gui_layer *gui_layer,
173                                SDL_Rect *dest_rect)
174 {
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;
178   }
179 }
180 
181 /**********************************************************************//**
182   Translate dest_rect from gui_layer's to global screen coordinates.
183 **************************************************************************/
layer_rect_to_screen_rect(struct gui_layer * gui_layer,SDL_Rect * dest_rect)184 void layer_rect_to_screen_rect(struct gui_layer *gui_layer,
185                                SDL_Rect *dest_rect)
186 {
187   if (gui_layer) {
188     dest_rect->x = dest_rect->x + gui_layer->dest_rect.x;
189     dest_rect->y = dest_rect->y + gui_layer->dest_rect.y;
190   }
191 }
192 
193 /* ============ Freeciv sdl graphics function =========== */
194 
195 /**************************************************************************
196   Execute alphablit.
197 **************************************************************************/
alphablit(SDL_Surface * src,SDL_Rect * srcrect,SDL_Surface * dst,SDL_Rect * dstrect,unsigned char alpha_mod)198 int alphablit(SDL_Surface *src, SDL_Rect *srcrect,
199               SDL_Surface *dst, SDL_Rect *dstrect,
200               unsigned char alpha_mod)
201 {
202   int ret;
203 
204   if (src == NULL || dst == NULL) {
205     return 1;
206   }
207 
208   SDL_SetSurfaceAlphaMod(src, alpha_mod);
209 
210   ret = SDL_BlitSurface(src, srcrect, dst, dstrect);
211 
212   if (ret) {
213     log_error("SDL_BlitSurface() fails: %s", SDL_GetError());
214   }
215 
216   return ret;
217 }
218 
219 /**************************************************************************
220   Execute alphablit to the main surface
221 **************************************************************************/
screen_blit(SDL_Surface * src,SDL_Rect * srcrect,SDL_Rect * dstrect,unsigned char alpha_mod)222 int screen_blit(SDL_Surface *src, SDL_Rect *srcrect, SDL_Rect *dstrect,
223                 unsigned char alpha_mod)
224 {
225   render_dirty = TRUE;
226   return alphablit(src, srcrect, main_surface, dstrect, alpha_mod);
227 }
228 
229 /**************************************************************************
230   Create new surface (pRect->w x pRect->h size) and copy pRect area of
231   pSource.
232   if pRect == NULL then create copy of entire pSource.
233 **************************************************************************/
crop_rect_from_surface(SDL_Surface * pSource,SDL_Rect * pRect)234 SDL_Surface *crop_rect_from_surface(SDL_Surface *pSource,
235                                     SDL_Rect *pRect)
236 {
237   SDL_Surface *pNew = create_surf_with_format(pSource->format,
238                                               pRect ? pRect->w : pSource->w,
239                                               pRect ? pRect->h : pSource->h,
240                                               SDL_SWSURFACE);
241 
242   if (alphablit(pSource, pRect, pNew, NULL, 255) != 0) {
243     FREESURFACE(pNew);
244 
245     return NULL;
246   }
247 
248   return pNew;
249 }
250 
251 /**************************************************************************
252   Reduce the alpha of the final surface proportional to the alpha of the mask.
253   Thus if the mask has 50% alpha the final image will be reduced by 50% alpha.
254 
255   mask_offset_x, mask_offset_y is the offset of the mask relative to the
256   origin of the source image.  The pixel at (mask_offset_x,mask_offset_y)
257   in the mask image will be used to clip pixel (0,0) in the source image
258   which is pixel (-x,-y) in the new image.
259 **************************************************************************/
mask_surface(SDL_Surface * pSrc,SDL_Surface * pMask,int mask_offset_x,int mask_offset_y)260 SDL_Surface *mask_surface(SDL_Surface *pSrc, SDL_Surface *pMask,
261                           int mask_offset_x, int mask_offset_y)
262 {
263   SDL_Surface *pDest = NULL;
264   int row, col;
265   Uint32 *pSrc_Pixel = NULL;
266   Uint32 *pDest_Pixel = NULL;
267   Uint32 *pMask_Pixel = NULL;
268   unsigned char src_alpha, mask_alpha;
269 
270   pDest = copy_surface(pSrc);
271 
272   lock_surf(pSrc);
273   lock_surf(pMask);
274   lock_surf(pDest);
275 
276   pSrc_Pixel = (Uint32 *)pSrc->pixels;
277   pDest_Pixel = (Uint32 *)pDest->pixels;
278 
279   for (row = 0; row < pSrc->h; row++) {
280     pMask_Pixel = (Uint32 *)pMask->pixels
281                   + pMask->w * (row + mask_offset_y)
282                   + mask_offset_x;
283 
284     for (col = 0; col < pSrc->w; col++) {
285       src_alpha = (*pSrc_Pixel & pSrc->format->Amask) >> pSrc->format->Ashift;
286       mask_alpha = (*pMask_Pixel & pMask->format->Amask) >> pMask->format->Ashift;
287 
288       *pDest_Pixel = (*pSrc_Pixel & ~pSrc->format->Amask)
289         | (((src_alpha * mask_alpha) / 255) << pDest->format->Ashift);
290 
291       pSrc_Pixel++; pDest_Pixel++; pMask_Pixel++;
292     }
293   }
294 
295   unlock_surf(pDest);
296   unlock_surf(pMask);
297   unlock_surf(pSrc);
298 
299   return pDest;
300 }
301 
302 /**************************************************************************
303   Load a surface from file putting it in software mem.
304 **************************************************************************/
load_surf(const char * pFname)305 SDL_Surface *load_surf(const char *pFname)
306 {
307   SDL_Surface *pBuf;
308 
309   if (!pFname) {
310     return NULL;
311   }
312 
313   if ((pBuf = IMG_Load(pFname)) == NULL) {
314     log_error(_("load_surf: Failed to load graphic file %s!"), pFname);
315 
316     return NULL;
317   }
318 
319   return pBuf;
320 }
321 
322 /**************************************************************************
323    create an surface with format
324    MUST NOT BE USED IF NO SDLSCREEN IS SET
325 **************************************************************************/
create_surf_with_format(SDL_PixelFormat * pf,int width,int height,Uint32 flags)326 SDL_Surface *create_surf_with_format(SDL_PixelFormat *pf,
327                                      int width, int height,
328                                      Uint32 flags)
329 {
330   SDL_Surface *surf = SDL_CreateRGBSurface(flags, width, height,
331                                            pf->BitsPerPixel,
332                                            pf->Rmask,
333                                            pf->Gmask,
334                                            pf->Bmask, pf->Amask);
335 
336   if (surf == NULL) {
337     log_error(_("Unable to create Sprite (Surface) of size "
338                 "%d x %d %d Bits in format %d"),
339               width, height, pf->BitsPerPixel, flags);
340     return NULL;
341   }
342 
343   return surf;
344 }
345 
346 /**************************************************************************
347   Create surface with the same format as main window
348 **************************************************************************/
create_surf(int width,int height,Uint32 flags)349 SDL_Surface *create_surf(int width, int height, Uint32 flags)
350 {
351   return create_surf_with_format(main_surface->format, width, height, flags);
352 }
353 
354 /**************************************************************************
355   Convert surface to the main window format.
356 **************************************************************************/
convert_surf(SDL_Surface * surf_in)357 SDL_Surface *convert_surf(SDL_Surface *surf_in)
358 {
359   return SDL_ConvertSurface(surf_in, main_surface->format, 0);
360 }
361 
362 /**************************************************************************
363   create an surface with screen format and fill with color.
364   if pColor == NULL surface is filled with transparent white A = 128
365 **************************************************************************/
create_filled_surface(Uint16 w,Uint16 h,Uint32 iFlags,SDL_Color * pColor)366 SDL_Surface *create_filled_surface(Uint16 w, Uint16 h, Uint32 iFlags,
367                                    SDL_Color *pColor)
368 {
369   SDL_Surface *pNew;
370   SDL_Color color = {255, 255, 255, 128};
371 
372   pNew = create_surf(w, h, iFlags);
373 
374   if (!pNew) {
375     return NULL;
376   }
377 
378   if (!pColor) {
379     /* pColor->unused == ALPHA */
380     pColor = &color;
381   }
382 
383   SDL_FillRect(pNew, NULL,
384                SDL_MapRGBA(pNew->format, pColor->r, pColor->g, pColor->b,
385                            pColor->a));
386 
387   if (pColor->a != 255) {
388     SDL_SetSurfaceAlphaMod(pNew, pColor->a);
389   }
390 
391   return pNew;
392 }
393 
394 /**************************************************************************
395   fill surface with (0, 0, 0, 0), so the next blitting operation can set
396   the per pixel alpha
397 **************************************************************************/
clear_surface(SDL_Surface * pSurf,SDL_Rect * dstrect)398 int clear_surface(SDL_Surface *pSurf, SDL_Rect *dstrect)
399 {
400   /* SDL_FillRect might change the rectangle, so we create a copy */
401   if (dstrect) {
402     SDL_Rect _dstrect = *dstrect;
403 
404     return SDL_FillRect(pSurf, &_dstrect, SDL_MapRGBA(pSurf->format, 0, 0, 0, 0));
405   } else {
406     return SDL_FillRect(pSurf, NULL, SDL_MapRGBA(pSurf->format, 0, 0, 0, 0));
407   }
408 }
409 
410 /**************************************************************************
411   blit entire src [SOURCE] surface to destination [DEST] surface
412   on position : [iDest_x],[iDest_y] using it's actual alpha and
413   color key settings.
414 **************************************************************************/
blit_entire_src(SDL_Surface * pSrc,SDL_Surface * pDest,Sint16 iDest_x,Sint16 iDest_y)415 int blit_entire_src(SDL_Surface * pSrc, SDL_Surface * pDest,
416                     Sint16 iDest_x, Sint16 iDest_y)
417 {
418   SDL_Rect dest_rect = { iDest_x, iDest_y, 0, 0 };
419 
420   return alphablit(pSrc, NULL, pDest, &dest_rect, 255);
421 }
422 
423 /**************************************************************************
424   Get pixel
425   Return the pixel value at (x, y)
426   NOTE: The surface must be locked before calling this!
427 **************************************************************************/
getpixel(SDL_Surface * pSurface,Sint16 x,Sint16 y)428 Uint32 getpixel(SDL_Surface *pSurface, Sint16 x, Sint16 y)
429 {
430   if (!pSurface) {
431     return 0x0;
432   }
433 
434   switch (pSurface->format->BytesPerPixel) {
435   case 1:
436     return *(Uint8 *) ((Uint8 *) pSurface->pixels + y * pSurface->pitch + x);
437 
438   case 2:
439     return *((Uint16 *)pSurface->pixels + y * pSurface->pitch / sizeof(Uint16) + x);
440 
441   case 3:
442     {
443       /* Here ptr is the address to the pixel we want to retrieve */
444       Uint8 *ptr =
445         (Uint8 *) pSurface->pixels + y * pSurface->pitch + x * 3;
446 
447       if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
448         return ptr[0] << 16 | ptr[1] << 8 | ptr[2];
449       } else {
450         return ptr[0] | ptr[1] << 8 | ptr[2] << 16;
451       }
452     }
453   case 4:
454     return *((Uint32 *)pSurface->pixels + y * pSurface->pitch / sizeof(Uint32) + x);
455 
456   default:
457     return 0; /* shouldn't happen, but avoids warnings */
458   }
459 }
460 
461 /**************************************************************************
462   get first pixel
463   Return the pixel value at (0, 0)
464   NOTE: The surface must be locked before calling this!
465 **************************************************************************/
get_first_pixel(SDL_Surface * pSurface)466 Uint32 get_first_pixel(SDL_Surface *pSurface)
467 {
468   if (!pSurface) {
469     return 0;
470   }
471 
472   switch (pSurface->format->BytesPerPixel) {
473   case 1:
474     return *((Uint8 *)pSurface->pixels);
475 
476   case 2:
477     return *((Uint16 *)pSurface->pixels);
478 
479   case 3:
480     {
481       if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
482         return (((Uint8 *)pSurface->pixels)[0] << 16)
483           | (((Uint8 *)pSurface->pixels)[1] << 8)
484           | ((Uint8 *)pSurface->pixels)[2];
485       } else {
486         return ((Uint8 *)pSurface->pixels)[0]
487           | (((Uint8 *)pSurface->pixels)[1] << 8)
488           | (((Uint8 *)pSurface->pixels)[2] << 16);
489       }
490     }
491   case 4:
492     return *((Uint32 *)pSurface->pixels);
493 
494   default:
495     return 0; /* shouldn't happen, but avoids warnings */
496   }
497 }
498 
499 /* ===================================================================== */
500 
501 /**************************************************************************
502   initialize sdl with Flags
503 **************************************************************************/
init_sdl(int iFlags)504 void init_sdl(int iFlags)
505 {
506   bool error;
507 
508   Main.screen = NULL;
509   Main.guis = NULL;
510   Main.gui = NULL;
511   Main.map = NULL;
512   Main.dummy = NULL; /* can't create yet -- hope we don't need it */
513   Main.rects_count = 0;
514   Main.guis_count = 0;
515 
516   if (SDL_WasInit(SDL_INIT_AUDIO)) {
517     error = (SDL_InitSubSystem(iFlags) < 0);
518   } else {
519     error = (SDL_Init(iFlags) < 0);
520   }
521   if (error) {
522     log_fatal(_("Unable to initialize SDL2 library: %s"), SDL_GetError());
523     exit(EXIT_FAILURE);
524   }
525 
526   atexit(SDL_Quit);
527 
528   /* Initialize the TTF library */
529   if (TTF_Init() < 0) {
530     log_fatal(_("Unable to initialize SDL2_ttf library: %s"), SDL_GetError());
531     exit(EXIT_FAILURE);
532   }
533 
534   atexit(TTF_Quit);
535 }
536 
537 /**************************************************************************
538   Free screen buffers
539 **************************************************************************/
quit_sdl(void)540 void quit_sdl(void)
541 {
542   FC_FREE(Main.guis);
543   gui_layer_destroy(&Main.gui);
544   FREESURFACE(Main.map);
545   FREESURFACE(Main.dummy);
546 }
547 
548 /**************************************************************************
549   Switch to passed video mode.
550 **************************************************************************/
set_video_mode(int iWidth,int iHeight,int iFlags)551 int set_video_mode(int iWidth, int iHeight, int iFlags)
552 {
553   unsigned int flags;
554 
555   Main.screen = SDL_CreateWindow(_("SDL2 Client for Freeciv"),
556                                  SDL_WINDOWPOS_UNDEFINED,
557                                  SDL_WINDOWPOS_UNDEFINED,
558                                  iWidth, iHeight,
559                                  0);
560 
561   if (iFlags & SDL_WINDOW_FULLSCREEN) {
562     SDL_DisplayMode mode;
563 
564     /* Use SDL_WINDOW_FULLSCREEN_DESKTOP instead of real SDL_WINDOW_FULLSCREEN */
565     SDL_SetWindowFullscreen(Main.screen, SDL_WINDOW_FULLSCREEN_DESKTOP);
566     SDL_GetWindowDisplayMode(Main.screen, &mode);
567     iWidth = mode.w;
568     iHeight = mode.h;
569   }
570 
571   main_surface = SDL_CreateRGBSurface(0, iWidth, iHeight, 32,
572 #if SDL_BYTEORDER != SDL_LIL_ENDIAN
573                 0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF
574 #else
575                 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000
576 #endif
577 );
578 
579   Main.map = SDL_CreateRGBSurface(0, iWidth, iHeight, 32,
580 #if SDL_BYTEORDER != SDL_LIL_ENDIAN
581                 0x0000FF00, 0x00FF0000, 0xFF000000, 0x000000FF
582 #else
583                 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000
584 #endif
585 );
586 
587   if (gui_options.gui_sdl2_swrenderer) {
588     flags = SDL_RENDERER_SOFTWARE;
589   } else {
590     flags = 0;
591   }
592 
593   Main.renderer = SDL_CreateRenderer(Main.screen, -1, flags);
594 
595   Main.maintext = SDL_CreateTexture(Main.renderer,
596                                     SDL_PIXELFORMAT_ARGB8888,
597                                     SDL_TEXTUREACCESS_STREAMING,
598                                     iWidth, iHeight);
599 
600   if (Main.gui) {
601     FREESURFACE(Main.gui->surface);
602     Main.gui->surface = create_surf(iWidth, iHeight, SDL_SWSURFACE);
603   } else {
604     Main.gui = add_gui_layer(iWidth, iHeight);
605   }
606 
607   clear_surface(Main.gui->surface, NULL);
608 
609   return 0;
610 }
611 
612 /**************************************************************************
613   Render from main surface with screen renderer.
614 **************************************************************************/
update_main_screen(void)615 void update_main_screen(void)
616 {
617   if (render_dirty) {
618     SDL_UpdateTexture(Main.maintext, NULL,
619                       main_surface->pixels, main_surface->pitch);
620     SDL_RenderClear(Main.renderer);
621     SDL_RenderCopy(Main.renderer, Main.maintext, NULL, NULL);
622     SDL_RenderPresent(Main.renderer);
623 
624     render_dirty = FALSE;
625   }
626 }
627 
628 /**************************************************************************
629   Return width of the main window
630 **************************************************************************/
main_window_width(void)631 int main_window_width(void)
632 {
633   return main_surface->w;
634 }
635 
636 /**************************************************************************
637   Return height of the main window
638 **************************************************************************/
main_window_height(void)639 int main_window_height(void)
640 {
641   return main_surface->h;
642 }
643 
644 /**************************************************************************
645                            Fill Rect with RGBA color
646 **************************************************************************/
647 #define MASK565 0xf7de
648 #define MASK555 0xfbde
649 
650 /* 50% alpha (128) */
651 #define BLEND16_50( d, s , mask )       \
652         (((( s & mask ) + ( d & mask )) >> 1) + ( s & d & ( ~mask & 0xffff)))
653 
654 #define BLEND2x16_50( d, s , mask )     \
655         (((( s & (mask | mask << 16)) + ( d & ( mask | mask << 16 ))) >> 1) + \
656         ( s & d & ( ~(mask | mask << 16))))
657 
658 /**************************************************************************
659   Fill rectangle for "565" format surface
660 **************************************************************************/
__FillRectAlpha565(SDL_Surface * pSurface,SDL_Rect * pRect,SDL_Color * pColor)661 static int __FillRectAlpha565(SDL_Surface *pSurface, SDL_Rect *pRect,
662                               SDL_Color *pColor)
663 {
664   Uint32 y, end;
665   Uint32 *start;
666   Uint32 *pixel;
667   register Uint32 D, S =
668       SDL_MapRGB(pSurface->format, pColor->r, pColor->g, pColor->b);
669   register Uint32 A = pColor->a >> 3;
670 
671   S &= 0xFFFF;
672 
673   lock_surf(pSurface);
674   if (pRect == NULL) {
675     end = pSurface->w * pSurface->h;
676     pixel = pSurface->pixels;
677     if (A == 16) { /* A == 128 >> 3 */
678       /* this code don't work (A == 128) */
679       if (end & 0x1) { /* end % 2 */
680         D = *pixel;
681         *pixel++ = BLEND16_50(D, S, MASK565);
682         end--;
683       }
684 
685       S = S | S << 16;
686       for (y = 0; y < end; y += 2) {
687         D = *(Uint32 *) pixel;
688         *(Uint32 *) pixel = BLEND2x16_50(D, S, MASK565);
689         pixel += 2;
690       }
691     } else {
692       S = (S | S << 16) & 0x07e0f81f;
693       DUFFS_LOOP8(
694       {
695         D = *pixel;
696         D = (D | D << 16) & 0x07e0f81f;
697         D += (S - D) * A >> 5;
698         D &= 0x07e0f81f;
699         *pixel++ = (D | (D >> 16)) & 0xFFFF;
700       }, end);
701     }
702   } else {
703     /* correct pRect size */
704     if (pRect->x < 0) {
705       pRect->w += pRect->x;
706       pRect->x = 0;
707     } else {
708       if (pRect->x >= pSurface->w - pRect->w) {
709         pRect->w = pSurface->w - pRect->x;
710       }
711     }
712 
713     if (pRect->y < 0) {
714       pRect->h += pRect->y;
715       pRect->y = 0;
716     } else {
717       if (pRect->y >= pSurface->h - pRect->h) {
718         pRect->h = pSurface->h - pRect->y;
719       }
720     }
721 
722     start = pixel = (Uint32 *) pSurface->pixels +
723       (pRect->y * pSurface->pitch) + pRect->x / 2;
724 
725     if (A == 16) { /* A == 128 >> 3 */
726       /* this code don't work (A == 128) */
727       S = S | S << 16;
728       for (y = 0; y < pRect->h; y++) {
729         end = 0;
730 
731         if (pRect->w & 0x1) {
732           D = *pixel;
733           *pixel++ = BLEND16_50(D, (S & 0xFFFF), MASK565);
734           end++;
735         }
736 
737         for (; end < pRect->w; end += 2) {
738           D = *(Uint32 *) pixel;
739           *(Uint32 *) pixel = BLEND2x16_50(D, S, MASK565);
740           pixel += 2;
741         }
742 
743         pixel = start + pSurface->pitch;
744         start = pixel;
745       }
746     } else {
747       y = 0;
748       S = (S | S << 16) & 0x07e0f81f;
749       y = pRect->h;
750       end = pRect->w;
751 
752       while (y--) {
753         DUFFS_LOOP8(
754         {
755           D = *pixel;
756           D = (D | D << 16) & 0x07e0f81f;
757           D += (S - D) * A >> 5;
758           D &= 0x07e0f81f;
759           *pixel++ = (D | (D >> 16)) & 0xFFFF;
760         }, end);
761 
762         pixel = start + pSurface->pitch;
763         start = pixel;
764       } /* while */
765     }
766 
767   }
768 
769   unlock_surf(pSurface);
770   return 0;
771 }
772 
773 /**************************************************************************
774   Fill rectangle for "555" format surface
775 **************************************************************************/
__FillRectAlpha555(SDL_Surface * pSurface,SDL_Rect * pRect,SDL_Color * pColor)776 static int __FillRectAlpha555(SDL_Surface *pSurface, SDL_Rect *pRect,
777                               SDL_Color *pColor)
778 {
779   Uint32 y, end;
780   Uint32 *start, *pixel;
781   register Uint32 D, S =
782       SDL_MapRGB(pSurface->format, pColor->r, pColor->g, pColor->b);
783   register Uint32 A = pColor->a >> 3;
784 
785   S &= 0xFFFF;
786 
787   lock_surf(pSurface);
788 
789   if (pRect == NULL) {
790     end = pSurface->w * pSurface->h;
791     pixel = pSurface->pixels;
792     if (A == 16) { /* A == 128 >> 3 */
793       if (end & 0x1) {
794         D = *pixel;
795         *pixel++ = BLEND16_50(D, S, MASK555);
796         end--;
797       }
798 
799       S = S | S << 16;
800       for (y = 0; y < end; y += 2) {
801         D = *pixel;
802         *pixel = BLEND2x16_50(D, S, MASK555);
803         pixel += 2;
804       }
805     } else {
806       S = (S | S << 16) & 0x03e07c1f;
807       DUFFS_LOOP8(
808       {
809         D = *pixel;
810         D = (D | D << 16) & 0x03e07c1f;
811         D += (S - D) * A >> 5;
812         D &= 0x03e07c1f;
813         *pixel++ = (D | (D >> 16)) & 0xFFFF;
814       }, end);
815     }
816   } else {
817     /* correct pRect size */
818     if (pRect->x < 0) {
819       pRect->w += pRect->x;
820       pRect->x = 0;
821     } else {
822       if (pRect->x >= pSurface->w - pRect->w) {
823         pRect->w = pSurface->w - pRect->x;
824       }
825     }
826 
827     if (pRect->y < 0) {
828       pRect->h += pRect->y;
829       pRect->y = 0;
830     } else {
831       if (pRect->y >= pSurface->h - pRect->h) {
832         pRect->h = pSurface->h - pRect->y;
833       }
834     }
835 
836     start = pixel = (Uint32 *) pSurface->pixels +
837       (pRect->y * pSurface->pitch) + pRect->x / 2;
838 
839     if (A == 16) { /* A == 128 >> 3 */
840       S = S | S << 16;
841       for (y = 0; y < pRect->h; y++) {
842         end = 0;
843 
844         if (pRect->w & 0x1) {
845           D = *pixel;
846           *pixel++ = BLEND16_50(D, (S & 0xFFFF), MASK555);
847           end++;
848         }
849 
850         for (; end < pRect->w; end += 2) {
851           D = *(Uint32 *) pixel;
852           *(Uint32 *) pixel = BLEND2x16_50(D, S, MASK555);
853           pixel += 2;
854         }
855 
856         pixel = start + pSurface->pitch;
857         start = pixel;
858       }
859     } else {
860 
861       S = (S | S << 16) & 0x03e07c1f;
862       y = pRect->h;
863       end = pRect->w;
864 
865       while( y--) {
866         DUFFS_LOOP8(
867         {
868           D = *pixel;
869           D = (D | D << 16) & 0x03e07c1f;
870           D += (S - D) * A >> 5;
871           D &= 0x03e07c1f;
872           *pixel++ = (D | (D >> 16)) & 0xFFFF;
873         }, end);
874 
875         pixel = start + pSurface->pitch;
876         start = pixel;
877       } /* while */
878     }
879   }
880 
881   unlock_surf(pSurface);
882   return 0;
883 }
884 
885 /**************************************************************************
886   Fill rectangle for 32bit "8888" format surface
887 **************************************************************************/
__FillRectAlpha8888_32bit(SDL_Surface * pSurface,SDL_Rect * pRect,SDL_Color * pColor)888 static int __FillRectAlpha8888_32bit(SDL_Surface *pSurface, SDL_Rect *pRect,
889                                      SDL_Color *pColor)
890 {
891   register Uint32 A = pColor->a;
892   register Uint32 dSIMD1, dSIMD2;
893   register Uint32 sSIMD1, sSIMD2 = SDL_MapRGB(pSurface->format,
894                                               pColor->r, pColor->g,
895                                               pColor->b);
896   Uint32 y, end, A_Dst, A_Mask = pSurface->format->Amask;
897   Uint32 *start, *pixel;
898 
899   sSIMD1 = sSIMD2 & 0x00FF00FF;
900 
901   lock_surf(pSurface);
902 
903   if (pRect == NULL) {
904     end = pSurface->w * pSurface->h;
905     pixel = (Uint32 *) pSurface->pixels;
906     if (A == 128) { /* 50% A */
907       DUFFS_LOOP8(
908       {
909         dSIMD2 = *pixel;
910         A_Dst = dSIMD2 & A_Mask;
911         *pixel++ = ((((sSIMD2 & 0x00fefefe) + (dSIMD2 & 0x00fefefe)) >> 1)
912                     + (sSIMD2 & dSIMD2 & 0x00010101)) | A_Dst;
913       }, end);
914     } else {
915       sSIMD2 &= 0xFF00;
916       sSIMD2 = sSIMD2 >> 8 | sSIMD2 << 8;
917       DUFFS_LOOP_DOUBLE2(
918         {
919           dSIMD2 = *pixel;
920           A_Dst = dSIMD2 & A_Mask;
921           dSIMD1 = dSIMD2 & 0x00FF00FF;
922           dSIMD1 += (sSIMD1 - dSIMD1) * A >> 8;
923           dSIMD1 &= 0x00FF00FF;
924           dSIMD2 &= 0xFF00;
925           dSIMD2 += (((sSIMD2 << 8) & 0xFF00) - dSIMD2) * A >> 8;
926           dSIMD2 &= 0xFF00;
927           *pixel++ = dSIMD1 | dSIMD2 | A_Dst;
928       },{
929           dSIMD1 = *pixel;
930           A_Dst = dSIMD1 & A_Mask;
931           dSIMD1 &= 0x00FF00FF;
932           dSIMD1 += (sSIMD1 - dSIMD1) * A >> 8;
933           dSIMD1 &= 0x00FF00FF;
934 
935           dSIMD2 = ((*pixel & 0xFF00) >> 8)| ((pixel[1] & 0xFF00) << 8);
936           dSIMD2 += (sSIMD2 - dSIMD2) * A >> 8;
937           dSIMD2 &= 0x00FF00FF;
938 
939           *pixel++ = dSIMD1 | ((dSIMD2 << 8) & 0xFF00) | A_Dst;
940 
941           dSIMD1 = *pixel;
942           A_Dst = dSIMD1 & A_Mask;
943           dSIMD1 &= 0x00FF00FF;
944           dSIMD1 += (sSIMD1 - dSIMD1) * A >> 8;
945           dSIMD1 &= 0x00FF00FF;
946 
947           *pixel++ = dSIMD1 | ((dSIMD2 >> 8) & 0xFF00) | A_Dst;
948       }, end);
949     }
950   } else {
951     /* correct pRect size */
952     if (pRect->x < 0) {
953       pRect->w += pRect->x;
954       pRect->x = 0;
955     } else {
956       if (pRect->x >= pSurface->w - pRect->w) {
957         pRect->w = pSurface->w - pRect->x;
958       }
959     }
960 
961     if (pRect->y < 0) {
962       pRect->h += pRect->y;
963       pRect->y = 0;
964     } else {
965       if (pRect->y >= pSurface->h - pRect->h) {
966         pRect->h = pSurface->h - pRect->y;
967       }
968     }
969 
970     start = pixel = (Uint32 *) pSurface->pixels +
971       (pRect->y * (pSurface->pitch >> 2)) + pRect->x;
972 
973     if (A == 128) { /* 50% A */
974       y = pRect->h;
975       end = pRect->w;
976       while (y--) {
977         DUFFS_LOOP4(
978         {
979           dSIMD2 = *pixel;
980           A_Dst = dSIMD2 & A_Mask;
981           *pixel++ = ((((sSIMD2 & 0x00fefefe) + (dSIMD2 & 0x00fefefe)) >> 1)
982                       + (sSIMD2 & dSIMD2 & 0x00010101)) | A_Dst;
983         }, end);
984         pixel = start + (pSurface->pitch >> 2);
985         start = pixel;
986       }
987     } else {
988       y = pRect->h;
989       end = pRect->w;
990 
991       sSIMD2 &= 0xFF00;
992       sSIMD2 = sSIMD2 >> 8 | sSIMD2 << 8;
993 
994       while (y--) {
995         DUFFS_LOOP_DOUBLE2(
996         {
997           dSIMD2 = *pixel;
998           A_Dst = dSIMD2 & A_Mask;
999           dSIMD1 = dSIMD2 & 0x00FF00FF;
1000           dSIMD1 += (sSIMD1 - dSIMD1) * A >> 8;
1001           dSIMD1 &= 0x00FF00FF;
1002           dSIMD2 &= 0xFF00;
1003           dSIMD2 += (((sSIMD2 << 8) & 0xFF00) - dSIMD2) * A >> 8;
1004           dSIMD2 &= 0xFF00;
1005           *pixel++ = dSIMD1 | dSIMD2 | A_Dst;
1006         },{
1007           dSIMD1 = *pixel;
1008           A_Dst = dSIMD1 & A_Mask;
1009           dSIMD1 &= 0x00FF00FF;
1010           dSIMD1 += (sSIMD1 - dSIMD1) * A >> 8;
1011           dSIMD1 &= 0x00FF00FF;
1012 
1013           dSIMD2 = ((*pixel & 0xFF00) >> 8)| ((pixel[1] & 0xFF00) << 8);
1014           dSIMD2 += (sSIMD2 - dSIMD2) * A >> 8;
1015           dSIMD2 &= 0x00FF00FF;
1016 
1017           *pixel++ = dSIMD1 | ((dSIMD2 << 8) & 0xFF00) | A_Dst;
1018 
1019           dSIMD1 = *pixel;
1020           A_Dst = dSIMD1 & A_Mask;
1021           dSIMD1 &= 0x00FF00FF;
1022           dSIMD1 += (sSIMD1 - dSIMD1) * A >> 8;
1023           dSIMD1 &= 0x00FF00FF;
1024 
1025           *pixel++ = dSIMD1 | ((dSIMD2 >> 8) & 0xFF00) | A_Dst;
1026         }, end);
1027 
1028         pixel = start + (pSurface->pitch >> 2);
1029         start = pixel;
1030       } /* while */
1031     }
1032   }
1033 
1034   unlock_surf(pSurface);
1035   return 0;
1036 }
1037 
1038 /**************************************************************************
1039   Fill rectangle for 32bit "888" format surface
1040 **************************************************************************/
__FillRectAlpha888_32bit(SDL_Surface * pSurface,SDL_Rect * pRect,SDL_Color * pColor)1041 static int __FillRectAlpha888_32bit(SDL_Surface *pSurface, SDL_Rect *pRect,
1042                                     SDL_Color *pColor)
1043 {
1044   register Uint32 A = pColor->a;
1045   register Uint32 dSIMD1, dSIMD2;
1046   register Uint32 sSIMD1, sSIMD2 = SDL_MapRGB(pSurface->format,
1047                                               pColor->r, pColor->g,
1048                                               pColor->b);
1049   Uint32 y, end;
1050   Uint32 *start, *pixel;
1051 
1052   sSIMD1 = sSIMD2 & 0x00FF00FF;
1053 
1054   lock_surf(pSurface);
1055 
1056   if (pRect == NULL) {
1057     end = pSurface->w * pSurface->h;
1058     pixel = (Uint32 *) pSurface->pixels;
1059     if (A == 128) { /* 50% A */
1060       for (y = 0; y < end; y++) {
1061         dSIMD2 = *pixel;
1062         *pixel++ = ((((sSIMD2 & 0x00fefefe) + (dSIMD2 & 0x00fefefe)) >> 1)
1063                     + (sSIMD2 & dSIMD2 & 0x00010101)) | 0xFF000000;
1064       }
1065     } else {
1066       sSIMD2 &= 0xFF00;
1067       sSIMD2 = sSIMD2 >> 8 | sSIMD2 << 8;
1068       DUFFS_LOOP_DOUBLE2(
1069         {
1070           dSIMD2 = *pixel;
1071           dSIMD1 = dSIMD2 & 0x00FF00FF;
1072           dSIMD1 += (sSIMD1 - dSIMD1) * A >> 8;
1073           dSIMD1 &= 0x00FF00FF;
1074           dSIMD2 &= 0xFF00;
1075           dSIMD2 += (((sSIMD2 << 8) & 0xFF00) - dSIMD2) * A >> 8;
1076           dSIMD2 &= 0xFF00;
1077           *pixel++ = dSIMD1 | dSIMD2 | 0xFF000000;
1078       },{
1079           dSIMD1 = *pixel & 0x00FF00FF;
1080           dSIMD1 += (sSIMD1 - dSIMD1) * A >> 8;
1081           dSIMD1 &= 0x00FF00FF;
1082 
1083           dSIMD2 = ((*pixel & 0xFF00) >> 8)| ((pixel[1] & 0xFF00) << 8);
1084           dSIMD2 += (sSIMD2 - dSIMD2) * A >> 8;
1085           dSIMD2 &= 0x00FF00FF;
1086 
1087           *pixel++ = dSIMD1 | ((dSIMD2 << 8) & 0xFF00) | 0xFF000000;
1088 
1089           dSIMD1 = *pixel & 0x00FF00FF;
1090           dSIMD1 += (sSIMD1 - dSIMD1) * A >> 8;
1091           dSIMD1 &= 0x00FF00FF;
1092 
1093           *pixel++ = dSIMD1 | ((dSIMD2 >> 8) & 0xFF00) | 0xFF000000;
1094       }, end);
1095     }
1096   } else {
1097     /* correct pRect size */
1098     if (pRect->x < 0) {
1099       pRect->w += pRect->x;
1100       pRect->x = 0;
1101     } else {
1102       if (pRect->x >= pSurface->w - pRect->w) {
1103         pRect->w = pSurface->w - pRect->x;
1104       }
1105     }
1106 
1107     if (pRect->y < 0) {
1108       pRect->h += pRect->y;
1109       pRect->y = 0;
1110     } else {
1111       if (pRect->y >= pSurface->h - pRect->h) {
1112         pRect->h = pSurface->h - pRect->y;
1113       }
1114     }
1115 
1116     start = pixel = (Uint32 *) pSurface->pixels +
1117         (pRect->y * (pSurface->pitch >> 2)) + pRect->x;
1118 
1119     if (A == 128) { /* 50% A */
1120 
1121       for (y = 0; y < pRect->h; y++) {
1122 
1123         for (end = 0; end < pRect->w; end++) {
1124           dSIMD2 = *pixel;
1125           *pixel++ = ((((sSIMD2 & 0x00fefefe) + (dSIMD2 & 0x00fefefe)) >> 1)
1126                       + (sSIMD2 & dSIMD2 & 0x00010101)) | 0xFF000000;
1127         }
1128 
1129         pixel = start + (pSurface->pitch >> 2);
1130         start = pixel;
1131       }
1132     } else {
1133       y = pRect->h;
1134       end = pRect->w;
1135 
1136       sSIMD2 &= 0xFF00;
1137       sSIMD2 = sSIMD2 >> 8 | sSIMD2 << 8;
1138 
1139       while (y--) {
1140         DUFFS_LOOP_DOUBLE2(
1141         {
1142           dSIMD2 = *pixel;
1143           dSIMD1 = dSIMD2 & 0x00FF00FF;
1144           dSIMD1 += (sSIMD1 - dSIMD1) * A >> 8;
1145           dSIMD1 &= 0x00FF00FF;
1146           dSIMD2 &= 0xFF00;
1147           dSIMD2 += (((sSIMD2 << 8) & 0xFF00) - dSIMD2) * A >> 8;
1148           dSIMD2 &= 0xFF00;
1149           *pixel++ = dSIMD1 | dSIMD2 | 0xFF000000;
1150         },{
1151           dSIMD1 = *pixel & 0x00FF00FF;
1152           dSIMD1 += (sSIMD1 - dSIMD1) * A >> 8;
1153           dSIMD1 &= 0x00FF00FF;
1154 
1155           dSIMD2 = ((*pixel & 0xFF00) >> 8)| ((pixel[1] & 0xFF00) << 8);
1156           dSIMD2 += (sSIMD2 - dSIMD2) * A >> 8;
1157           dSIMD2 &= 0x00FF00FF;
1158 
1159           *pixel++ = dSIMD1 | ((dSIMD2 << 8) & 0xFF00) | 0xFF000000;
1160 
1161           dSIMD1 = *pixel & 0x00FF00FF;
1162           dSIMD1 += (sSIMD1 - dSIMD1) * A >> 8;
1163           dSIMD1 &= 0x00FF00FF;
1164 
1165           *pixel++ = dSIMD1 | ((dSIMD2 >> 8) & 0xFF00) | 0xFF000000;
1166         }, end);
1167 
1168         pixel = start + (pSurface->pitch >> 2);
1169         start = pixel;
1170 
1171       } /* while */
1172     }
1173   }
1174 
1175   unlock_surf(pSurface);
1176   return 0;
1177 }
1178 
1179 /**************************************************************************
1180   Fill rectangle for 24bit "888" format surface
1181 **************************************************************************/
__FillRectAlpha888_24bit(SDL_Surface * pSurface,SDL_Rect * pRect,SDL_Color * pColor)1182 static int __FillRectAlpha888_24bit(SDL_Surface *pSurface, SDL_Rect *pRect,
1183                                     SDL_Color *pColor)
1184 {
1185   Uint32 y, end;
1186   Uint8 *start, *pixel;
1187   register Uint32 P, D, S1, S2 = SDL_MapRGB(pSurface->format,
1188                                             pColor->r, pColor->g,
1189                                             pColor->b);
1190   register Uint32 A = pColor->a;
1191 
1192   S1 = S2 & 0x00FF00FF;
1193 
1194   S2 &= 0xFF00;
1195 
1196   lock_surf(pSurface);
1197 
1198   if (pRect == NULL) {
1199     end = pSurface->w * pSurface->h;
1200     pixel = (Uint8 *) pSurface->pixels;
1201 
1202     for (y = 0; y < end; y++) {
1203       D = (pixel[0] << 16) + (pixel[1] << 8) + pixel[2];
1204 
1205       P = D & 0x00FF00FF;
1206       P += (S1 - P) * A >> 8;
1207       P &= 0x00ff00ff;
1208 
1209       D = (D & 0xFF00);
1210       D += (S2 - D) * A >> 8;
1211       D &= 0xFF00;
1212 
1213       P = P | D;
1214 
1215       /* Fix me to little - big EDIAN */
1216 
1217       pixel[0] = P & 0xff;
1218       pixel[1] = (P >> 8) & 0xff;
1219       pixel[2] = (P >> 16) & 0xff;
1220 
1221       pixel += 3;
1222     }
1223 
1224   } else {
1225     /* correct pRect size */
1226     if (pRect->x < 0) {
1227       pRect->w += pRect->x;
1228       pRect->x = 0;
1229     } else {
1230       if (pRect->x >= pSurface->w - pRect->w) {
1231         pRect->w = pSurface->w - pRect->x;
1232       }
1233     }
1234 
1235     if (pRect->y < 0) {
1236       pRect->h += pRect->y;
1237       pRect->y = 0;
1238     } else {
1239       if (pRect->y >= pSurface->h - pRect->h) {
1240         pRect->h = pSurface->h - pRect->y;
1241       }
1242     }
1243 
1244     end = pRect->w * pRect->h;
1245     start = pixel = (Uint8 *) pSurface->pixels +
1246       (pRect->y * pSurface->pitch) + pRect->x * 3;
1247 
1248     y = 0;
1249     while (y != pRect->h) {
1250       D = (pixel[0] << 16) + (pixel[1] << 8) + pixel[2];
1251 
1252       P = D & 0x00FF00FF;
1253       P += (S1 - P) * A >> 8;
1254       P &= 0x00ff00ff;
1255 
1256       D = (D & 0xFF00);
1257       D += (S2 - D) * A >> 8;
1258       D &= 0xFF00;
1259 
1260       P = P | D;
1261 
1262       /* Fix me to little - big EDIAN */
1263 
1264       pixel[0] = P & 0xff;
1265       pixel[1] = (P >> 8) & 0xff;
1266       pixel[2] = (P >> 16) & 0xff;
1267 
1268       if ((pixel - start) == (pRect->w * 3)) {
1269         pixel = start + pSurface->pitch;
1270         start = pixel;
1271         y++;
1272       } else {
1273         pixel += 3;
1274       }
1275     }
1276   }
1277 
1278   unlock_surf(pSurface);
1279 
1280   return 0;
1281 }
1282 
1283 /**************************************************************************
1284   Fill rectangle with color with alpha channel.
1285 **************************************************************************/
fill_rect_alpha(SDL_Surface * pSurface,SDL_Rect * pRect,SDL_Color * pColor)1286 int fill_rect_alpha(SDL_Surface *pSurface, SDL_Rect *pRect,
1287                     SDL_Color *pColor)
1288 {
1289   if (pRect && (pRect->x < - pRect->w || pRect->x >= pSurface->w
1290                 || pRect->y < - pRect->h || pRect->y >= pSurface->h)) {
1291     return -2;
1292   }
1293 
1294   if (pColor->a == 255) {
1295     return SDL_FillRect(pSurface, pRect,
1296                         SDL_MapRGB(pSurface->format, pColor->r, pColor->g, pColor->b));
1297   }
1298 
1299   if (!pColor->a) {
1300     return -3;
1301   }
1302 
1303   switch (pSurface->format->BytesPerPixel) {
1304   case 1:
1305     /* PORT ME */
1306     return -1;
1307 
1308   case 2:
1309     if (pSurface->format->Gmask == 0x7E0) {
1310       return __FillRectAlpha565(pSurface, pRect, pColor);
1311     } else {
1312       if (pSurface->format->Gmask == 0x3E0) {
1313         return __FillRectAlpha555(pSurface, pRect, pColor);
1314       } else {
1315         return -1;
1316       }
1317     }
1318     break;
1319 
1320   case 3:
1321     return __FillRectAlpha888_24bit(pSurface, pRect, pColor);
1322 
1323   case 4:
1324     if (pSurface->format->Amask) {
1325       return __FillRectAlpha8888_32bit(pSurface, pRect, pColor);
1326     } else {
1327       return __FillRectAlpha888_32bit(pSurface, pRect, pColor);
1328     }
1329   }
1330 
1331   return -1;
1332 }
1333 
1334 /**************************************************************************
1335   Make rectangle region sane. Return TRUE if result is sane.
1336 **************************************************************************/
correct_rect_region(SDL_Rect * pRect)1337 bool correct_rect_region(SDL_Rect *pRect)
1338 {
1339   int ww = pRect->w, hh = pRect->h;
1340 
1341   if (pRect->x < 0) {
1342     ww += pRect->x;
1343     pRect->x = 0;
1344   }
1345 
1346   if (pRect->y < 0) {
1347     hh += pRect->y;
1348     pRect->y = 0;
1349   }
1350 
1351   if (pRect->x + ww > main_window_width()) {
1352     ww = main_window_width() - pRect->x;
1353   }
1354 
1355   if (pRect->y + hh > main_window_height()) {
1356     hh = main_window_height() - pRect->y;
1357   }
1358 
1359   /* End Correction */
1360 
1361   if (ww <= 0 || hh <= 0) {
1362     return FALSE; /* suprise :) */
1363   } else {
1364     pRect->w = ww;
1365     pRect->h = hh;
1366   }
1367 
1368   return TRUE;
1369 }
1370 
1371 /**************************************************************************
1372   Return whether coordinates are in rectangle.
1373 **************************************************************************/
is_in_rect_area(int x,int y,SDL_Rect rect)1374 bool is_in_rect_area(int x, int y, SDL_Rect rect)
1375 {
1376   return ((x >= rect.x) && (x < rect.x + rect.w)
1377           && (y >= rect.y) && (y < rect.y + rect.h));
1378 }
1379 
1380 /* ===================================================================== */
1381 
1382 /**************************************************************************
1383   Get visible rectangle from surface.
1384 **************************************************************************/
get_smaller_surface_rect(SDL_Surface * pSurface)1385 SDL_Rect get_smaller_surface_rect(SDL_Surface *pSurface)
1386 {
1387   SDL_Rect src;
1388   int w, h, x, y;
1389   Uint16 minX, maxX, minY, maxY;
1390   Uint32 colorkey;
1391 
1392   fc_assert(pSurface != NULL);
1393 
1394   minX = pSurface->w;
1395   maxX = 0;
1396   minY = pSurface->h;
1397   maxY = 0;
1398   SDL_GetColorKey(pSurface, &colorkey);
1399 
1400   lock_surf(pSurface);
1401 
1402   switch(pSurface->format->BytesPerPixel) {
1403     case 1:
1404     {
1405       Uint8 *pixel = (Uint8 *)pSurface->pixels;
1406       Uint8 *start = pixel;
1407       x = 0;
1408       y = 0;
1409       w = pSurface->w;
1410       h = pSurface->h;
1411       while (h--) {
1412         do {
1413           if (*pixel != colorkey) {
1414             if (minY > y) {
1415               minY = y;
1416             }
1417 
1418             if (minX > x) {
1419               minX = x;
1420             }
1421             break;
1422           }
1423           pixel++;
1424           x++;
1425         } while( --w > 0 );
1426         w = pSurface->w;
1427         x = 0;
1428         y++;
1429         pixel = start + pSurface->pitch;
1430         start = pixel;
1431       }
1432 
1433       w = pSurface->w;
1434       h = pSurface->h;
1435       x = w - 1;
1436       y = h - 1;
1437       pixel = (Uint8 *)((Uint8 *)pSurface->pixels + (y * pSurface->pitch) + x);
1438       start = pixel;
1439       while (h--) {
1440         do {
1441           if (*pixel != colorkey) {
1442             if (maxY < y) {
1443               maxY = y;
1444             }
1445 
1446             if (maxX < x) {
1447               maxX = x;
1448             }
1449             break;
1450           }
1451           pixel--;
1452           x--;
1453         } while( --w > 0 );
1454         w = pSurface->w;
1455         x = w - 1;
1456         y--;
1457         pixel = start - pSurface->pitch;
1458         start = pixel;
1459       }
1460     }
1461     break;
1462     case 2:
1463     {
1464       Uint16 *pixel = (Uint16 *)pSurface->pixels;
1465       Uint16 *start = pixel;
1466 
1467       x = 0;
1468       y = 0;
1469       w = pSurface->w;
1470       h = pSurface->h;
1471       while (h--) {
1472         do {
1473           if (*pixel != colorkey) {
1474             if (minY > y) {
1475               minY = y;
1476             }
1477 
1478             if (minX > x) {
1479               minX = x;
1480             }
1481             break;
1482           }
1483           pixel++;
1484           x++;
1485         } while( --w > 0 );
1486         w = pSurface->w;
1487         x = 0;
1488         y++;
1489         pixel = start + pSurface->pitch / 2;
1490         start = pixel;
1491      }
1492 
1493       w = pSurface->w;
1494       h = pSurface->h;
1495       x = w - 1;
1496       y = h - 1;
1497       pixel = ((Uint16 *)pSurface->pixels + (y * pSurface->pitch / 2) + x);
1498       start = pixel;
1499       while (h--) {
1500         do {
1501           if (*pixel != colorkey) {
1502             if (maxY < y) {
1503               maxY = y;
1504             }
1505 
1506             if (maxX < x) {
1507               maxX = x;
1508             }
1509             break;
1510           }
1511           pixel--;
1512           x--;
1513         } while( --w > 0 );
1514         w = pSurface->w;
1515         x = w - 1;
1516         y--;
1517         pixel = start - pSurface->pitch / 2;
1518         start = pixel;
1519       }
1520     }
1521     break;
1522     case 3:
1523     {
1524       Uint8 *pixel = (Uint8 *)pSurface->pixels;
1525       Uint8 *start = pixel;
1526       Uint32 color;
1527 
1528       x = 0;
1529       y = 0;
1530       w = pSurface->w;
1531       h = pSurface->h;
1532       while (h--) {
1533         do {
1534           if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1535             color = (pixel[0] << 16 | pixel[1] << 8 | pixel[2]);
1536           } else {
1537             color = (pixel[0] | pixel[1] << 8 | pixel[2] << 16);
1538           }
1539           if (color != colorkey) {
1540             if (minY > y) {
1541               minY = y;
1542             }
1543 
1544             if (minX > x) {
1545               minX = x;
1546             }
1547             break;
1548           }
1549           pixel += 3;
1550           x++;
1551         } while( --w > 0 );
1552         w = pSurface->w;
1553         x = 0;
1554         y++;
1555         pixel = start + pSurface->pitch / 3;
1556         start = pixel;
1557       }
1558 
1559       w = pSurface->w;
1560       h = pSurface->h;
1561       x = w - 1;
1562       y = h - 1;
1563       pixel = (Uint8 *)((Uint8 *)pSurface->pixels + (y * pSurface->pitch) + x * 3);
1564       start = pixel;
1565       while (h--) {
1566         do {
1567           if (SDL_BYTEORDER == SDL_BIG_ENDIAN) {
1568             color = (pixel[0] << 16 | pixel[1] << 8 | pixel[2]);
1569           } else {
1570             color = (pixel[0] | pixel[1] << 8 | pixel[2] << 16);
1571           }
1572           if (color != colorkey) {
1573             if (maxY < y) {
1574               maxY = y;
1575             }
1576 
1577             if (maxX < x) {
1578               maxX = x;
1579             }
1580             break;
1581           }
1582           pixel -= 3;
1583           x--;
1584         } while( --w > 0 );
1585         w = pSurface->w;
1586         x = w - 1;
1587         y--;
1588         pixel = start - pSurface->pitch / 3;
1589         start = pixel;
1590      }
1591     }
1592     break;
1593     case 4:
1594     {
1595       Uint32 *pixel = (Uint32 *)pSurface->pixels;
1596       Uint32 *start = pixel;
1597 
1598       x = 0;
1599       y = 0;
1600       w = pSurface->w;
1601       h = pSurface->h;
1602       while(h--) {
1603         do {
1604           if (*pixel != colorkey) {
1605             if (minY > y) {
1606               minY = y;
1607             }
1608 
1609             if (minX > x) {
1610               minX = x;
1611             }
1612             break;
1613           }
1614           pixel++;
1615           x++;
1616         } while( --w > 0 );
1617         w = pSurface->w;
1618         x = 0;
1619         y++;
1620         pixel = start + pSurface->pitch / 4;
1621         start = pixel;
1622       }
1623 
1624       w = pSurface->w;
1625       h = pSurface->h;
1626       x = w - 1;
1627       y = h - 1;
1628       pixel = ((Uint32 *)pSurface->pixels + (y * pSurface->pitch / 4) + x);
1629       start = pixel;
1630       while (h--) {
1631         do {
1632           if (*pixel != colorkey) {
1633             if (maxY < y) {
1634               maxY = y;
1635             }
1636 
1637             if (maxX < x) {
1638               maxX = x;
1639             }
1640             break;
1641           }
1642           pixel--;
1643           x--;
1644         } while( --w > 0 );
1645         w = pSurface->w;
1646         x = w - 1;
1647         y--;
1648         pixel = start - pSurface->pitch / 4;
1649         start = pixel;
1650       }
1651     }
1652     break;
1653   }
1654 
1655   unlock_surf(pSurface);
1656   src.x = minX;
1657   src.y = minY;
1658   src.w = maxX - minX + 1;
1659   src.h = maxY - minY + 1;
1660 
1661   return src;
1662 }
1663 
1664 /**************************************************************************
1665   Create new surface that is just visible part of source surface.
1666 **************************************************************************/
crop_visible_part_from_surface(SDL_Surface * pSrc)1667 SDL_Surface *crop_visible_part_from_surface(SDL_Surface *pSrc)
1668 {
1669   SDL_Rect src = get_smaller_surface_rect(pSrc);
1670 
1671   return crop_rect_from_surface(pSrc, &src);
1672 }
1673 
1674 /**************************************************************************
1675   Scale surface.
1676 **************************************************************************/
ResizeSurface(const SDL_Surface * pSrc,Uint16 new_width,Uint16 new_height,int smooth)1677 SDL_Surface *ResizeSurface(const SDL_Surface *pSrc, Uint16 new_width,
1678                            Uint16 new_height, int smooth)
1679 {
1680   if (pSrc == NULL) {
1681     return NULL;
1682   }
1683 
1684   return zoomSurface((SDL_Surface*)pSrc,
1685                      (double)new_width / pSrc->w,
1686                      (double)new_height / pSrc->h,
1687                      smooth);
1688 }
1689 
1690 /**************************************************************************
1691   Resize a surface to fit into a box with the dimensions 'new_width' and a
1692   'new_height'. If 'scale_up' is FALSE, a surface that already fits into
1693   the box will not be scaled up to the boundaries of the box.
1694   If 'absolute_dimensions' is TRUE, the function returns a surface with the
1695   dimensions of the box and the scaled/original surface centered in it.
1696 **************************************************************************/
ResizeSurfaceBox(const SDL_Surface * pSrc,Uint16 new_width,Uint16 new_height,int smooth,bool scale_up,bool absolute_dimensions)1697 SDL_Surface *ResizeSurfaceBox(const SDL_Surface *pSrc,
1698                               Uint16 new_width, Uint16 new_height, int smooth,
1699                               bool scale_up, bool absolute_dimensions)
1700 {
1701   SDL_Surface *tmpSurface, *result;
1702 
1703   if (pSrc == NULL) {
1704     return NULL;
1705   }
1706 
1707   if (!((scale_up == FALSE) && ((new_width >= pSrc->w) && (new_height >= pSrc->h)))) {
1708     if ((new_width - pSrc->w) <= (new_height - pSrc->h)) {
1709       /* horizontal limit */
1710       tmpSurface = zoomSurface((SDL_Surface*)pSrc,
1711                                (double)new_width / pSrc->w,
1712                                (double)new_width / pSrc->w,
1713                                smooth);
1714     } else {
1715       /* vertical limit */
1716       tmpSurface = zoomSurface((SDL_Surface*)pSrc,
1717                                (double)new_height / pSrc->h,
1718                                (double)new_height / pSrc->h,
1719                                smooth);
1720     }
1721   } else {
1722     tmpSurface = zoomSurface((SDL_Surface*)pSrc,
1723                              1.0,
1724                              1.0,
1725                              smooth);
1726   }
1727 
1728   if (absolute_dimensions) {
1729     SDL_Rect area = {
1730       (new_width - tmpSurface->w) / 2,
1731       (new_height - tmpSurface->h) / 2,
1732       0, 0
1733     };
1734 
1735     result = create_surf(new_width, new_height, SDL_SWSURFACE);
1736     alphablit(tmpSurface, NULL, result, &area, 255);
1737     FREESURFACE(tmpSurface);
1738   } else {
1739     result = tmpSurface;
1740   }
1741 
1742   return result;
1743 }
1744 
1745 /**************************************************************************
1746   Return copy of the surface
1747 **************************************************************************/
copy_surface(SDL_Surface * src)1748 SDL_Surface *copy_surface(SDL_Surface *src)
1749 {
1750   SDL_Surface *dst;
1751 
1752   dst = SDL_CreateRGBSurface(0, src->w, src->h, src->format->BitsPerPixel,
1753                              src->format->Rmask, src->format->Gmask,
1754                              src->format->Bmask, src->format->Amask);
1755 
1756   SDL_BlitSurface(src, NULL, dst, NULL);
1757 
1758   return dst;
1759 }
1760 
1761 /* ============ Freeciv game graphics function =========== */
1762 
1763 /**************************************************************************
1764   Return whether the client supports given view type
1765 **************************************************************************/
is_view_supported(enum ts_type type)1766 bool is_view_supported(enum ts_type type)
1767 {
1768   switch (type) {
1769   case TS_ISOMETRIC:
1770   case TS_OVERHEAD:
1771     return TRUE;
1772   }
1773 
1774   return FALSE;
1775 }
1776 
1777 /**************************************************************************
1778   Load intro sprites. Not used in SDL-client.
1779 **************************************************************************/
load_intro_gfx(void)1780 void load_intro_gfx(void)
1781 {
1782   /* nothing */
1783 }
1784 
1785 /**************************************************************************
1786   Frees the introductory sprites.
1787 **************************************************************************/
free_intro_radar_sprites(void)1788 void free_intro_radar_sprites(void)
1789 {
1790   /* nothing */
1791 }
1792 
1793 /**************************************************************************
1794   Create colored frame
1795 **************************************************************************/
create_frame(SDL_Surface * dest,Sint16 left,Sint16 top,Sint16 width,Sint16 height,SDL_Color * pcolor)1796 void create_frame(SDL_Surface *dest, Sint16 left, Sint16 top,
1797                   Sint16 width, Sint16 height,
1798                   SDL_Color *pcolor)
1799 {
1800   struct color gsdl2_color = { .color = pcolor };
1801   struct sprite *vertical = create_sprite(1, height, &gsdl2_color);
1802   struct sprite *horizontal = create_sprite(width, 1, &gsdl2_color);
1803   SDL_Rect tmp,dst = { left, top, 0, 0 };
1804 
1805   tmp = dst;
1806   alphablit(vertical->psurface, NULL, dest, &tmp, 255);
1807 
1808   dst.x += width - 1;
1809   tmp = dst;
1810   alphablit(vertical->psurface, NULL, dest, &tmp, 255);
1811 
1812   dst.x = left;
1813   tmp = dst;
1814   alphablit(horizontal->psurface, NULL, dest, &tmp, 255);
1815 
1816   dst.y += height - 1;
1817   tmp = dst;
1818   alphablit(horizontal->psurface, NULL, dest, &tmp, 255);
1819 
1820   free_sprite(horizontal);
1821   free_sprite(vertical);
1822 }
1823 
1824 /**************************************************************************
1825   Create single colored line
1826 **************************************************************************/
create_line(SDL_Surface * dest,Sint16 x0,Sint16 y0,Sint16 x1,Sint16 y1,SDL_Color * pcolor)1827 void create_line(SDL_Surface *dest, Sint16 x0, Sint16 y0, Sint16 x1, Sint16 y1,
1828                  SDL_Color *pcolor)
1829 {
1830   int xl = x0 < x1 ? x0 : x1;
1831   int xr = x0 < x1 ? x1 : x0;
1832   int yt = y0 < y1 ? y0 : y1;
1833   int yb = y0 < y1 ? y1 : y0;
1834   int w = (xr - xl) + 1;
1835   int h = (yb - yt) + 1;
1836   struct sprite *spr;
1837   SDL_Rect dst = { xl, yt, w, h };
1838   SDL_Color *pcol;
1839   struct color gsdl2_color;
1840   int l = MAX((xr - xl) + 1, (yb - yt) + 1);
1841   int i;
1842 
1843   pcol = fc_malloc(sizeof(pcol));
1844   pcol->r = pcolor->r;
1845   pcol->g = pcolor->g;
1846   pcol->b = pcolor->b;
1847   pcol->a = 0; /* Fill with transparency */
1848 
1849   gsdl2_color.color = pcol;
1850   spr = create_sprite(w, h, &gsdl2_color);
1851 
1852   lock_surf(spr->psurface);
1853 
1854   /* Set off transparency from pixels belonging to the line */
1855   if ((x0 <= x1 && y0 <= y1)
1856       || (x1 <= x0 && y1 <= y0)) {
1857     for (i = 0; i < l; i++) {
1858       int cx = (xr - xl) * i / l;
1859       int cy = (yb - yt) * i / l;
1860 
1861       *((Uint32 *)spr->psurface->pixels + spr->psurface->w * cy + cx)
1862         |= (pcolor->a << spr->psurface->format->Ashift);
1863     }
1864   } else {
1865     for (i = 0; i < l; i++) {
1866       int cx = (xr - xl) * i / l;
1867       int cy = yb - yt - (yb - yt) * i / l;
1868 
1869       *((Uint32 *)spr->psurface->pixels + spr->psurface->w * cy + cx)
1870         |= (pcolor->a << spr->psurface->format->Ashift);
1871     }
1872   }
1873 
1874   unlock_surf(spr->psurface);
1875 
1876   alphablit(spr->psurface, NULL, dest, &dst, 255);
1877 
1878   free_sprite(spr);
1879   free(pcol);
1880 }
1881