/* Create a masked surface from the given transparent sprite and mask. The sprite must be at least as wide as the mask plus mask offset. */ static SDL_Surface * create_masked_transp_surface(const sprite_t *sprite, const sprite_t *mask, int mask_off) { void *s_data = (uint8_t *)sprite + sizeof(sprite_t); size_t s_width = le16toh(sprite->w); size_t s_height = le16toh(sprite->h); /* Unpack */ size_t unpack_size = s_width * s_height; uint8_t *unpack = calloc(unpack_size, sizeof(uint8_t)); if (unpack == NULL) abort(); gfx_unpack_transparent_sprite(unpack, s_data, unpack_size, 0); size_t m_width = le16toh(mask->w); size_t m_height = le16toh(mask->h); uint8_t *s_copy = calloc(m_width * m_height, sizeof(uint8_t)); if (s_copy == NULL) abort(); size_t to_copy = m_width * min(m_height, s_height); uint8_t *copy_dest = s_copy; uint8_t *copy_src = unpack + mask_off; while (to_copy) { memcpy(copy_dest, copy_src, m_width * sizeof(uint8_t)); to_copy -= m_width; copy_dest += m_width; copy_src += s_width; } free(unpack); /* Mask */ void *m_data = (uint8_t *)mask + sizeof(sprite_t); /* Unpack mask */ size_t m_unpack_size = m_width * m_height; uint8_t *m_unpack = calloc(m_unpack_size, sizeof(uint8_t)); if (m_unpack == NULL) abort(); gfx_unpack_mask_sprite(m_unpack, m_data, m_unpack_size); /* Fill alpha value from mask data */ for (int y = 0; y < m_height; y++) { for (int x = 0; x < m_width; x++) { if (!m_unpack[y*m_width+x]) { *(s_copy + y * m_width + x) = 0; } } } free(m_unpack); SDL_Surface *surf = create_surface_from_data(s_copy, m_width, m_height, 1); free(s_copy); return surf; }
surface_t * skia_draw_masked_sprite(const sprite_t *sprite, int x, int y, const sprite_t *mask, surface_t *surface, frame_t *dest) { // LOGI("skia_draw_masked_sprite x=%d y=%d", x, y); if (dest == NULL) { LOGE("skia_draw_masked_sprite: dest is NULL"); return 0; } if (dest->skCanvas == NULL) { LOGE("skia_draw_masked_sprite: dest->skCanvas is NULL"); return 0; } size_t m_width = le16toh(mask->w); size_t m_height = le16toh(mask->h); size_t s_width = le16toh(sprite->w); size_t s_height = le16toh(sprite->h); SkAutoMalloc auto_s_copy (m_width * m_height); uint8_t* s_copy = static_cast<uint8_t*>(auto_s_copy.get()); if (s_copy == NULL) { LOGE("skia_draw_masked_sprite: out of memory"); return 0; } void *s_data = (uint8_t *)sprite + sizeof(sprite_t); size_t to_copy = m_width * m_height; size_t s_size = s_width * s_height; uint8_t *copy_dest = s_copy; while (to_copy) { size_t s = to_copy < s_size ? to_copy : s_size; memcpy(copy_dest, s_data, s * sizeof(uint8_t)); // copy from beginning again to_copy -= s; copy_dest += s; } // Mask void *m_data = (uint8_t *)mask + sizeof(sprite_t); /* Unpack mask */ size_t unpack_size = m_width * m_height; SkAutoMalloc auto_m_unpack (unpack_size); uint8_t* m_unpack = static_cast<uint8_t*>(auto_m_unpack.get()); if (m_unpack == NULL) { LOGE("m_unpack is NULL"); return 0; } gfx_unpack_mask_sprite(m_unpack, m_data, unpack_size); // Fill alpha value from mask data for (int y = 0; y < m_height; y++) { for (int x = 0; x < m_width; x++) { if (m_unpack[y*m_width+x] == 0) { s_copy[y*m_width+x] = 0; } } } SkBitmap bitmap; bitmap.setConfig(SkBitmap::kIndex8_Config, m_width, m_height); bitmap.setPixels(s_copy, g_color_table.get()); x += le16toh(mask->x); y += le16toh(mask->y); SkRect src_rect; src_rect.fLeft = 0; src_rect.fTop = 0; src_rect.fRight = SkIntToScalar(m_width); src_rect.fBottom = SkIntToScalar(m_height); SkRect dst_rect; dst_rect.fLeft = x; dst_rect.fTop = y; dst_rect.fRight = x + SkIntToScalar(m_width); dst_rect.fBottom = y + SkIntToScalar(m_height); ((SkCanvas*)dest->skCanvas)->drawBitmapRectToRect(bitmap, &src_rect, dst_rect, NULL); return 0; }
void sdl_draw_overlay_sprite(const sprite_t *sprite, int x, int y, int y_off, frame_t *dest) { int r; x += le16toh(sprite->x) + dest->clip.x; y += le16toh(sprite->y) + dest->clip.y; const surface_id_t id = { .sprite = sprite, .mask = NULL, .offset = 0 }; surface_t **surface = surface_ht_store(&overlay_sprite_cache, &id); if (*surface == NULL) { *surface = malloc(sizeof(surface_t)); if (*surface == NULL) abort(); (*surface)->surf = create_overlay_surface(sprite); } SDL_Surface *surf = (*surface)->surf; SDL_Rect src_rect = { 0, y_off, surf->w, surf->h - y_off }; SDL_Rect dest_rect = { x, y + y_off, 0, 0 }; SDL_SetClipRect(dest->surf, &dest->clip); /* Blit sprite */ r = SDL_BlitSurface(surf, &src_rect, dest->surf, &dest_rect); if (r < 0) { LOGE("sdl-video", "BlitSurface error: %s.", SDL_GetError()); } #if 0 /* Bounding box */ sdl_draw_rect(x, y + y_off, surf->w, surf->h - y_off, 1, dest); #endif } static SDL_Surface * create_masked_surface(const sprite_t *sprite, const sprite_t *mask) { size_t m_width = le16toh(mask->w); size_t m_height = le16toh(mask->h); size_t s_width = le16toh(sprite->w); size_t s_height = le16toh(sprite->h); void *s_data = (uint8_t *)sprite + sizeof(sprite_t); uint8_t *s_copy = malloc(m_width * m_height * sizeof(uint8_t)); if (s_copy == NULL) abort(); size_t to_copy = m_width * m_height; uint8_t *copy_dest = s_copy; while (to_copy) { size_t s = min(to_copy, s_width * s_height); memcpy(copy_dest, s_data, s * sizeof(uint8_t)); to_copy -= s; copy_dest += s; } /* Mask */ void *m_data = (uint8_t *)mask + sizeof(sprite_t); /* Unpack mask */ size_t unpack_size = m_width * m_height; uint8_t *m_unpack = calloc(unpack_size, sizeof(uint8_t)); if (m_unpack == NULL) abort(); gfx_unpack_mask_sprite(m_unpack, m_data, unpack_size); /* Fill alpha value from mask data */ for (int y = 0; y < m_height; y++) { for (int x = 0; x < m_width; x++) { if (!m_unpack[y*m_width+x]) { *(s_copy + y * m_width + x) = 0; } } } free(m_unpack); SDL_Surface *surf = create_surface_from_data(s_copy, (int)m_width, (int)m_height, 1); free(s_copy); return surf; }