From 8340a5b04420d2c456618245371cc6e268e5fa5d Mon Sep 17 00:00:00 2001 From: Andrei Karas Date: Fri, 2 Jun 2017 20:26:43 +0300 Subject: Add custom image to image blit function based on fuction from sdl_gfx SDL_gfxBlitRGBA. --- src/resources/sdlgfxblitfunc.cpp | 537 +++++++++++++++++++++++++++++++ src/resources/sdlgfxblitfunc.h | 42 +++ src/resources/sdlimagehelper.cpp | 16 +- src/resources/sdlimagehelper_unittest.cc | 78 +++++ 4 files changed, 671 insertions(+), 2 deletions(-) create mode 100644 src/resources/sdlgfxblitfunc.cpp create mode 100644 src/resources/sdlgfxblitfunc.h (limited to 'src/resources') diff --git a/src/resources/sdlgfxblitfunc.cpp b/src/resources/sdlgfxblitfunc.cpp new file mode 100644 index 000000000..77c67bbc4 --- /dev/null +++ b/src/resources/sdlgfxblitfunc.cpp @@ -0,0 +1,537 @@ +/* + * The ManaPlus Client + * Copyright (C) 2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + +SDL_gfxBlitFunc: custom blitters (part of SDL_gfx library) + +LGPL (c) A. Schiffler + +*/ + +#ifndef USE_SDL2 +#include "resources/sdlgfxblitfunc.h" + +#include "utils/checkutils.h" + +#include +#include + +#include "debug.h" + +#define GFX_DUFFS_LOOP4(pixel_copy_increment, width) \ + int n = (width+3)/4; \ + switch (width & 3) \ + { \ + case 0: do { \ + pixel_copy_increment; \ + case 3: pixel_copy_increment; \ + case 2: pixel_copy_increment; \ + case 1: pixel_copy_increment; \ + default: ; \ + } while (--n > 0 ); \ + } + +namespace +{ + typedef struct + { + Uint8 *s_pixels; + int s_width; + int s_height; + int s_skip; + Uint8 *d_pixels; + int d_width; + int d_height; + int d_skip; + void *aux_data; + SDL_PixelFormat *src; + Uint8 *table; + SDL_PixelFormat *dst; + } SDL_gfxBlitInfo; + + static unsigned int GFX_ALPHA_ADJUST_ARRAY[256] = + { + 0, /* 0 */ + 15, /* 1 */ + 22, /* 2 */ + 27, /* 3 */ + 31, /* 4 */ + 35, /* 5 */ + 39, /* 6 */ + 42, /* 7 */ + 45, /* 8 */ + 47, /* 9 */ + 50, /* 10 */ + 52, /* 11 */ + 55, /* 12 */ + 57, /* 13 */ + 59, /* 14 */ + 61, /* 15 */ + 63, /* 16 */ + 65, /* 17 */ + 67, /* 18 */ + 69, /* 19 */ + 71, /* 20 */ + 73, /* 21 */ + 74, /* 22 */ + 76, /* 23 */ + 78, /* 24 */ + 79, /* 25 */ + 81, /* 26 */ + 82, /* 27 */ + 84, /* 28 */ + 85, /* 29 */ + 87, /* 30 */ + 88, /* 31 */ + 90, /* 32 */ + 91, /* 33 */ + 93, /* 34 */ + 94, /* 35 */ + 95, /* 36 */ + 97, /* 37 */ + 98, /* 38 */ + 99, /* 39 */ + 100, /* 40 */ + 102, /* 41 */ + 103, /* 42 */ + 104, /* 43 */ + 105, /* 44 */ + 107, /* 45 */ + 108, /* 46 */ + 109, /* 47 */ + 110, /* 48 */ + 111, /* 49 */ + 112, /* 50 */ + 114, /* 51 */ + 115, /* 52 */ + 116, /* 53 */ + 117, /* 54 */ + 118, /* 55 */ + 119, /* 56 */ + 120, /* 57 */ + 121, /* 58 */ + 122, /* 59 */ + 123, /* 60 */ + 124, /* 61 */ + 125, /* 62 */ + 126, /* 63 */ + 127, /* 64 */ + 128, /* 65 */ + 129, /* 66 */ + 130, /* 67 */ + 131, /* 68 */ + 132, /* 69 */ + 133, /* 70 */ + 134, /* 71 */ + 135, /* 72 */ + 136, /* 73 */ + 137, /* 74 */ + 138, /* 75 */ + 139, /* 76 */ + 140, /* 77 */ + 141, /* 78 */ + 141, /* 79 */ + 142, /* 80 */ + 143, /* 81 */ + 144, /* 82 */ + 145, /* 83 */ + 146, /* 84 */ + 147, /* 85 */ + 148, /* 86 */ + 148, /* 87 */ + 149, /* 88 */ + 150, /* 89 */ + 151, /* 90 */ + 152, /* 91 */ + 153, /* 92 */ + 153, /* 93 */ + 154, /* 94 */ + 155, /* 95 */ + 156, /* 96 */ + 157, /* 97 */ + 158, /* 98 */ + 158, /* 99 */ + 159, /* 100 */ + 160, /* 101 */ + 161, /* 102 */ + 162, /* 103 */ + 162, /* 104 */ + 163, /* 105 */ + 164, /* 106 */ + 165, /* 107 */ + 165, /* 108 */ + 166, /* 109 */ + 167, /* 110 */ + 168, /* 111 */ + 168, /* 112 */ + 169, /* 113 */ + 170, /* 114 */ + 171, /* 115 */ + 171, /* 116 */ + 172, /* 117 */ + 173, /* 118 */ + 174, /* 119 */ + 174, /* 120 */ + 175, /* 121 */ + 176, /* 122 */ + 177, /* 123 */ + 177, /* 124 */ + 178, /* 125 */ + 179, /* 126 */ + 179, /* 127 */ + 180, /* 128 */ + 181, /* 129 */ + 182, /* 130 */ + 182, /* 131 */ + 183, /* 132 */ + 184, /* 133 */ + 184, /* 134 */ + 185, /* 135 */ + 186, /* 136 */ + 186, /* 137 */ + 187, /* 138 */ + 188, /* 139 */ + 188, /* 140 */ + 189, /* 141 */ + 190, /* 142 */ + 190, /* 143 */ + 191, /* 144 */ + 192, /* 145 */ + 192, /* 146 */ + 193, /* 147 */ + 194, /* 148 */ + 194, /* 149 */ + 195, /* 150 */ + 196, /* 151 */ + 196, /* 152 */ + 197, /* 153 */ + 198, /* 154 */ + 198, /* 155 */ + 199, /* 156 */ + 200, /* 157 */ + 200, /* 158 */ + 201, /* 159 */ + 201, /* 160 */ + 202, /* 161 */ + 203, /* 162 */ + 203, /* 163 */ + 204, /* 164 */ + 205, /* 165 */ + 205, /* 166 */ + 206, /* 167 */ + 206, /* 168 */ + 207, /* 169 */ + 208, /* 170 */ + 208, /* 171 */ + 209, /* 172 */ + 210, /* 173 */ + 210, /* 174 */ + 211, /* 175 */ + 211, /* 176 */ + 212, /* 177 */ + 213, /* 178 */ + 213, /* 179 */ + 214, /* 180 */ + 214, /* 181 */ + 215, /* 182 */ + 216, /* 183 */ + 216, /* 184 */ + 217, /* 185 */ + 217, /* 186 */ + 218, /* 187 */ + 218, /* 188 */ + 219, /* 189 */ + 220, /* 190 */ + 220, /* 191 */ + 221, /* 192 */ + 221, /* 193 */ + 222, /* 194 */ + 222, /* 195 */ + 223, /* 196 */ + 224, /* 197 */ + 224, /* 198 */ + 225, /* 199 */ + 225, /* 200 */ + 226, /* 201 */ + 226, /* 202 */ + 227, /* 203 */ + 228, /* 204 */ + 228, /* 205 */ + 229, /* 206 */ + 229, /* 207 */ + 230, /* 208 */ + 230, /* 209 */ + 231, /* 210 */ + 231, /* 211 */ + 232, /* 212 */ + 233, /* 213 */ + 233, /* 214 */ + 234, /* 215 */ + 234, /* 216 */ + 235, /* 217 */ + 235, /* 218 */ + 236, /* 219 */ + 236, /* 220 */ + 237, /* 221 */ + 237, /* 222 */ + 238, /* 223 */ + 238, /* 224 */ + 239, /* 225 */ + 240, /* 226 */ + 240, /* 227 */ + 241, /* 228 */ + 241, /* 229 */ + 242, /* 230 */ + 242, /* 231 */ + 243, /* 232 */ + 243, /* 233 */ + 244, /* 234 */ + 244, /* 235 */ + 245, /* 236 */ + 245, /* 237 */ + 246, /* 238 */ + 246, /* 239 */ + 247, /* 240 */ + 247, /* 241 */ + 248, /* 242 */ + 248, /* 243 */ + 249, /* 244 */ + 249, /* 245 */ + 250, /* 246 */ + 250, /* 247 */ + 251, /* 248 */ + 251, /* 249 */ + 252, /* 250 */ + 252, /* 251 */ + 253, /* 252 */ + 253, /* 253 */ + 254, /* 254 */ + 255 /* 255 */ + }; +} + +static void _SDL_gfxBlitBlitterRGBA(SDL_gfxBlitInfo *info) +{ + int width = info->d_width; + int height = info->d_height; + Uint8 *src = info->s_pixels; + int srcskip = info->s_skip; + Uint8 *dst = info->d_pixels; + int dstskip = info->d_skip; + SDL_PixelFormat *srcfmt = info->src; + + while (height--) + { + GFX_DUFFS_LOOP4( + { + Uint32 pixel; + uint32_t sR; + uint32_t sG; + uint32_t sB; + uint32_t sA; + uint32_t dR; + uint32_t dG; + uint32_t dB; + uint32_t dA; + uint32_t sAA; + + pixel = *(reinterpret_cast(src)); + sR = ((pixel & srcfmt->Rmask) >> srcfmt->Rshift); + sG = ((pixel & srcfmt->Gmask) >> srcfmt->Gshift); + sB = ((pixel & srcfmt->Bmask) >> srcfmt->Bshift); + sA = ((pixel & srcfmt->Amask) >> srcfmt->Ashift); + + pixel = *(reinterpret_cast(dst)); + dR = pixel & 0xff; + dG = ((pixel & 0xff00) >> 8); + dB = ((pixel & 0xff0000) >> 16); + dA = ((pixel & 0xff000000) >> 24); + + sAA = GFX_ALPHA_ADJUST_ARRAY[sA & 255]; + dR = (((sR - dR) * (sAA)) / 255) + dR; + dG = (((sG - dG) * (sAA)) / 255) + dG; + dB = (((sB - dB) * (sAA)) / 255) + dB; + dA |= sAA; + + *(reinterpret_cast(dst)) = dR | + (dG << 8) | + (dB << 16) | + (dA << 24); + + src += 4; + dst += 4; + }, width); + src += srcskip; + dst += dstskip; + } +} + +static int _SDL_gfxBlitRGBACall(SDL_Surface *src, + SDL_Rect *srcrect, + SDL_Surface *dst, + SDL_Rect *dstrect) +{ + /* + * Set up source and destination buffer pointers, then blit + */ + if (srcrect->w && srcrect->h) + { + SDL_gfxBlitInfo info; + + /* + * Set up the blit information + */ + info.s_pixels = static_cast(src->pixels) + src->offset + + static_cast(srcrect->y) * src->pitch + + static_cast(srcrect->x) * src->format->BytesPerPixel; + info.s_width = srcrect->w; + info.s_height = srcrect->h; + info.s_skip = CAST_S32(src->pitch - info.s_width * + src->format->BytesPerPixel); + info.d_pixels = static_cast(dst->pixels) + dst->offset + + static_cast(dstrect->y) * dst->pitch + + static_cast(dstrect->x) * dst->format->BytesPerPixel; + info.d_width = dstrect->w; + info.d_height = dstrect->h; + info.d_skip = CAST_S32(dst->pitch - info.d_width * + dst->format->BytesPerPixel); + info.aux_data = NULL; + info.src = src->format; + info.table = NULL; + info.dst = dst->format; + + /* + * Run the actual software blitter + */ + _SDL_gfxBlitBlitterRGBA(&info); + return 1; + } + + return (0); +} + +int SDLgfxBlitRGBA(SDL_Surface *src, + SDL_Rect *srcrect, + SDL_Surface *dst, + SDL_Rect *dstrect) +{ + SDL_Rect sr; + SDL_Rect dr; + int srcx; + int srcy; + int w; + int h; + + /* + * Make sure the surfaces aren't locked + */ + if (!src || !dst) + { + reportAlways("SDLgfxBlitRGBA: passed a NULL surface"); + return -1; + } + + /* + * If the destination rectangle is NULL, use the entire dest surface + */ + if (dstrect == nullptr) + { + dr.x = 0; + dr.y = 0; + dr.w = dst->w; + dr.h = dst->h; + } + else + { + dr = *dstrect; + } + + /* + * Clip the source rectangle to the source surface + */ + if (srcrect) + { + int maxw; + int maxh; + + srcx = srcrect->x; + w = srcrect->w; + maxw = src->w - srcx; + if (maxw < w) + w = maxw; + + srcy = srcrect->y; + h = srcrect->h; + maxh = src->h - srcy; + if (maxh < h) + h = maxh; + + } + else + { + srcx = 0; + srcy = 0; + w = src->w; + h = src->h; + } + + /* + * Clip the destination rectangle against the clip rectangle + */ + SDL_Rect *clip = &dst->clip_rect; + int dx; + int dy; + + dx = clip->x - dr.x; + if (dx > 0) + { + w -= dx; + dr.x += dx; + srcx += dx; + } + dx = dr.x + w - clip->x - clip->w; + if (dx > 0) + w -= dx; + + dy = clip->y - dr.y; + if (dy > 0) + { + h -= dy; + dr.y += dy; + srcy += dy; + } + dy = dr.y + h - clip->y - clip->h; + if (dy > 0) + h -= dy; + + if (w > 0 && h > 0) + { + sr.x = srcx; + sr.y = srcy; + sr.w = dr.w = w; + sr.h = dr.h = h; + return _SDL_gfxBlitRGBACall(src, &sr, dst, &dr); + } + + return 0; +} + +#endif // USE_SDL2 diff --git a/src/resources/sdlgfxblitfunc.h b/src/resources/sdlgfxblitfunc.h new file mode 100644 index 000000000..dcf59fdca --- /dev/null +++ b/src/resources/sdlgfxblitfunc.h @@ -0,0 +1,42 @@ +/* + * The ManaPlus Client + * Copyright (C) 2017 The ManaPlus Developers + * + * This file is part of The ManaPlus Client. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + +SDL_gfxBlitFunc: custom blitters (part of SDL_gfx library) + +LGPL (c) A. Schiffler + +*/ + +#ifndef RESOURCE_SDLGFXBLITFUNC_H +#define RESOURCE_SDLGFXBLITFUNC_H + +struct SDL_Surface; +struct SDL_Rect; + +// src surface can be any format (most time 32 bit surface with any masks) +// dst surface always correct 32 sufraces (shared format for all) +int SDLgfxBlitRGBA(SDL_Surface *src, + SDL_Rect *srcrect, + SDL_Surface *dst, + SDL_Rect *dstrect); + +#endif // RESOURCE_SDLGFXBLITFUNC_H diff --git a/src/resources/sdlimagehelper.cpp b/src/resources/sdlimagehelper.cpp index bb339ce20..3c1653ca4 100644 --- a/src/resources/sdlimagehelper.cpp +++ b/src/resources/sdlimagehelper.cpp @@ -32,15 +32,22 @@ #include "utils/checkutils.h" #include "utils/sdlcheckutils.h" -#include #include -#include "debug.h" +#include "localconsts.h" + +#if SDL_BYTEORDER == SDL_LIL_ENDIAN +#include "resources/sdlgfxblitfunc.h" +#else // SDL_BYTEORDER == SDL_LIL_ENDIAN +#include +#endif // SDL_BYTEORDER == SDL_LIL_ENDIAN #ifndef SDL_BIG_ENDIAN #error missing SDL_endian.h #endif // SDL_BYTEORDER +#include "debug.h" + bool SDLImageHelper::mEnableAlphaCache = false; Image *SDLImageHelper::load(SDL_RWops *const rw, Dye const &dye) @@ -289,7 +296,12 @@ int SDLImageHelper::combineSurface(SDL_Surface *restrict const src, SDL_Surface *restrict const dst, SDL_Rect *restrict const dstrect) { +#if SDL_BYTEORDER == SDL_LIL_ENDIAN + return SDLgfxBlitRGBA(src, srcrect, dst, dstrect); +#else // SDL_BYTEORDER == SDL_LIL_ENDIAN + return SDL_gfxBlitRGBA(src, srcrect, dst, dstrect); +#endif // SDL_BYTEORDER == SDL_LIL_ENDIAN } void SDLImageHelper::copySurfaceToImage(const Image *const image, diff --git a/src/resources/sdlimagehelper_unittest.cc b/src/resources/sdlimagehelper_unittest.cc index e620a466d..2d4c52e73 100644 --- a/src/resources/sdlimagehelper_unittest.cc +++ b/src/resources/sdlimagehelper_unittest.cc @@ -450,6 +450,84 @@ TEST_CASE("sdlimagehelper combineSurface", "") MSDL_FreeSurface(surface2); } + SECTION("part mix 3") + { + SDL_Surface *surface1 = createSoftware32BitSurface(4, 4); + uint32_t *ptr1 = static_cast(surface1->pixels); + + ptr1[0] = 0x10203040; + ptr1[1] = 0x20304050; + ptr1[2] = 0x30405060; + ptr1[3] = 0x708090a0; + ptr1[4] = 0x8090a0b0; + ptr1[5] = 0x10112233; + ptr1[6] = 0x20003344; + ptr1[7] = 0x90a0b0c0; + ptr1[8] = 0xa0b0c0d0; + ptr1[9] = 0x30330055; + ptr1[10] = 0x40445500; + ptr1[11] = 0xb0c0d0e0; + ptr1[12] = 0xc0d0e0f0; + ptr1[13] = 0xd0e0f000; + ptr1[14] = 0xe0f00010; + ptr1[15] = 0xf0001020; + + SDL_Surface *surface2 = createSoftware32BitSurface(4, 4); + uint32_t *ptr2 = static_cast(surface2->pixels); + + ptr2[0] = 0x50003344; + ptr2[1] = 0x60330055; + ptr2[2] = 0x70445500; + ptr2[3] = 0x80112233; + ptr2[4] = 0x90111111; + ptr2[5] = 0x90111111; + ptr2[6] = 0xff000000; + ptr2[7] = 0xff000000; + ptr2[8] = 0xff000000; + ptr2[9] = 0xff000000; + ptr2[10] = 0xff000000; + ptr2[11] = 0xff000000; + ptr2[12] = 0xff000000; + ptr2[13] = 0xff000000; + ptr2[14] = 0xff000000; + ptr2[15] = 0xff000000; + + SDL_Rect rect1; + SDL_Rect rect2; + rect1.x = 1; + rect1.y = 1; + rect1.w = 2; + rect1.h = 2; + rect2.x = 0; + rect2.y = 0; + rect2.w = 2; + rect2.h = 2; + SDLImageHelper::combineSurface(surface2, + &rect2, + surface1, + &rect1); + + REQUIRE(ptr1[0] == 0x10203040); + REQUIRE(ptr1[1] == 0x20304050); + REQUIRE(ptr1[2] == 0x30405060); + REQUIRE(ptr1[3] == 0x708090a0); + REQUIRE(ptr1[4] == 0x8090a0b0); + REQUIRE(ptr1[5] == 0x9f082b3c); + REQUIRE(ptr1[6] == 0xbd1f144e); + REQUIRE(ptr1[7] == 0x90a0b0c0); + REQUIRE(ptr1[8] == 0xa0b0c0d0); + REQUIRE(ptr1[9] == 0xbf1b0d23); + REQUIRE(ptr1[10] == 0xff1f230c); + REQUIRE(ptr1[11] == 0xb0c0d0e0); + REQUIRE(ptr1[12] == 0xc0d0e0f0); + REQUIRE(ptr1[13] == 0xd0e0f000); + REQUIRE(ptr1[14] == 0xe0f00010); + REQUIRE(ptr1[15] == 0xf0001020); + + MSDL_FreeSurface(surface1); + MSDL_FreeSurface(surface2); + } + delete2(client); VirtFs::unmountDirSilent("data"); VirtFs::unmountDirSilent("../data"); -- cgit v1.2.3-60-g2f50