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