/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * 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 3 of the License, or * (at your option) 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 . * */ #include "ags/shared/gfx/bitmap.h" #include "ags/shared/util/memory.h" namespace AGS3 { namespace AGS { namespace Shared { // TODO: revise this construction later namespace BitmapHelper { Bitmap *CreateBitmap(int width, int height, int color_depth) { Bitmap *bitmap = new Bitmap(); if (!bitmap->Create(width, height, color_depth)) { delete bitmap; bitmap = nullptr; } return bitmap; } Bitmap *CreateClearBitmap(int width, int height, int color_depth, int clear_color) { Bitmap *bitmap = new Bitmap(); if (!bitmap->Create(width, height, color_depth)) { delete bitmap; return nullptr; } bitmap->Clear(clear_color); return bitmap; } Bitmap *CreateTransparentBitmap(int width, int height, int color_depth) { Bitmap *bitmap = new Bitmap(); if (!bitmap->CreateTransparent(width, height, color_depth)) { delete bitmap; bitmap = nullptr; } return bitmap; } Bitmap *CreateSubBitmap(Bitmap *src, const Rect &rc) { Bitmap *bitmap = new Bitmap(); if (!bitmap->CreateSubBitmap(src, rc)) { delete bitmap; bitmap = nullptr; } return bitmap; } Bitmap *CreateBitmapCopy(Bitmap *src, int color_depth) { Bitmap *bitmap = new Bitmap(); if (!bitmap->CreateCopy(src, color_depth)) { delete bitmap; bitmap = nullptr; } return bitmap; } Bitmap *LoadFromFile(const char *filename) { Bitmap *bitmap = new Bitmap(); if (!bitmap->LoadFromFile(filename)) { delete bitmap; bitmap = nullptr; } return bitmap; } Bitmap *LoadFromFile(PACKFILE *pf) { Bitmap *bitmap = new Bitmap(); if (!bitmap->LoadFromFile(pf)) { delete bitmap; bitmap = nullptr; } return bitmap; } Bitmap *AdjustBitmapSize(Bitmap *src, int width, int height) { int oldw = src->GetWidth(), oldh = src->GetHeight(); if ((oldw == width) && (oldh == height)) return src; Bitmap *bmp = BitmapHelper::CreateBitmap(width, height, src->GetColorDepth()); bmp->StretchBlt(src, RectWH(0, 0, oldw, oldh), RectWH(0, 0, width, height)); return bmp; } void MakeOpaque(Bitmap *bmp) { if (bmp->GetColorDepth() < 32) return; // no alpha channel for (int i = 0; i < bmp->GetHeight(); ++i) { uint32_t *line = reinterpret_cast(bmp->GetScanLineForWriting(i)); uint32_t *line_end = line + bmp->GetWidth(); for (uint32_t *px = line; px != line_end; ++px) *px = makeacol32(getr32(*px), getg32(*px), getb32(*px), 255); } } void MakeOpaqueSkipMask(Bitmap *bmp) { if (bmp->GetColorDepth() < 32) return; // no alpha channel for (int i = 0; i < bmp->GetHeight(); ++i) { uint32_t *line = reinterpret_cast(bmp->GetScanLineForWriting(i)); uint32_t *line_end = line + bmp->GetWidth(); for (uint32_t *px = line; px != line_end; ++px) if (*px != MASK_COLOR_32) *px = makeacol32(getr32(*px), getg32(*px), getb32(*px), 255); } } void ReplaceAlphaWithRGBMask(Bitmap *bmp) { if (bmp->GetColorDepth() < 32) return; // no alpha channel for (int i = 0; i < bmp->GetHeight(); ++i) { uint32_t *line = reinterpret_cast(bmp->GetScanLineForWriting(i)); uint32_t *line_end = line + bmp->GetWidth(); for (uint32_t *px = line; px != line_end; ++px) if (geta32(*px) == 0) *px = MASK_COLOR_32; } } // Functor that copies the "mask color" pixels from source to dest template struct PixelTransCpy { static const size_t BPP = BPP_; inline void operator ()(uint8_t *dst, const uint8_t *src, uint32_t mask_color, bool /*use_alpha*/) const { if (*(const TPx *)src == mask_color) *(TPx *)dst = mask_color; } }; // Functor that tells to never skip a pixel in the mask struct PixelNoSkip { inline bool operator ()(uint8_t * /*data*/, uint32_t /*mask_color*/, bool /*use_alpha*/) const { return false; } }; typedef PixelTransCpy PixelTransCpy8; typedef PixelTransCpy PixelTransCpy16; // Functor that copies the "mask color" pixels from source to dest, 24-bit depth struct PixelTransCpy24 { static const size_t BPP = 3; inline void operator ()(uint8_t *dst, const uint8_t *src, uint32_t mask_color, bool /*use_alpha*/) const { const uint8_t *mcol_ptr = (const uint8_t *)&mask_color; if (src[0] == mcol_ptr[0] && src[1] == mcol_ptr[1] && src[2] == mcol_ptr[2]) { dst[0] = mcol_ptr[0]; dst[1] = mcol_ptr[1]; dst[2] = mcol_ptr[2]; } } }; // Functor that copies the "mask color" pixels from source to dest, 32-bit depth, with alpha struct PixelTransCpy32 { static const size_t BPP = 4; inline void operator ()(uint8_t *dst, const uint8_t *src, uint32_t mask_color, bool use_alpha) const { if (*(const uint32_t *)src == mask_color) *(uint32_t *)dst = mask_color; else if (use_alpha) dst[3] = src[3]; // copy alpha channel else dst[3] = 0xFF; // set the alpha channel byte to opaque } }; // Functor that tells to skip pixels if they match the mask color or have alpha = 0 struct PixelTransSkip32 { inline bool operator ()(uint8_t *data, uint32_t mask_color, bool use_alpha) const { return *(const uint32_t *)data == mask_color || (use_alpha && data[3] == 0); } }; // Applies bitmap mask, using 2 functors: // - one that tells whether to skip current pixel; // - another that copies the color from src to dest template void ApplyMask(uint8_t *dst, const uint8_t *src, size_t pitch, size_t height, FnPxProc proc, FnSkip skip, uint32_t mask_color, bool dst_has_alpha, bool mask_has_alpha) { for (size_t y = 0; y < height; ++y) { for (size_t x = 0; x < pitch; x += FnPxProc::BPP, src += FnPxProc::BPP, dst += FnPxProc::BPP) { if (!skip(dst, mask_color, dst_has_alpha)) proc(dst, src, mask_color, mask_has_alpha); } } } void CopyTransparency(Bitmap *dst, const Bitmap *mask, bool dst_has_alpha, bool mask_has_alpha) { color_t mask_color = mask->GetMaskColor(); uint8_t *dst_ptr = dst->GetDataForWriting(); const uint8_t *src_ptr = mask->GetData(); const size_t bpp = mask->GetBPP(); const size_t pitch = mask->GetLineLength(); const size_t height = mask->GetHeight(); if (bpp == 1) ApplyMask(dst_ptr, src_ptr, pitch, height, PixelTransCpy8(), PixelNoSkip(), mask_color, dst_has_alpha, mask_has_alpha); else if (bpp == 2) ApplyMask(dst_ptr, src_ptr, pitch, height, PixelTransCpy16(), PixelNoSkip(), mask_color, dst_has_alpha, mask_has_alpha); else if (bpp == 3) ApplyMask(dst_ptr, src_ptr, pitch, height, PixelTransCpy24(), PixelNoSkip(), mask_color, dst_has_alpha, mask_has_alpha); else ApplyMask(dst_ptr, src_ptr, pitch, height, PixelTransCpy32(), PixelTransSkip32(), mask_color, dst_has_alpha, mask_has_alpha); } void ReadPixelsFromMemory(Bitmap *dst, const uint8_t *src_buffer, const size_t src_pitch, const size_t src_px_offset) { const size_t bpp = dst->GetBPP(); const size_t src_px_pitch = src_pitch / bpp; if (src_px_offset >= src_px_pitch) return; // nothing to copy Memory::BlockCopy(dst->GetDataForWriting(), dst->GetLineLength(), 0, src_buffer, src_pitch, src_px_offset * bpp, dst->GetHeight()); } } // namespace BitmapHelper } // namespace Shared } // namespace AGS } // namespace AGS3