Initial commit
This commit is contained in:
457
engines/ags/shared/gfx/allegro_bitmap.cpp
Normal file
457
engines/ags/shared/gfx/allegro_bitmap.cpp
Normal file
@@ -0,0 +1,457 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/config-manager.h"
|
||||
#include "common/savefile.h"
|
||||
#include "common/system.h"
|
||||
#include "ags/lib/aastr-0.1.1/aastr.h"
|
||||
#include "ags/shared/gfx/allegro_bitmap.h"
|
||||
#include "ags/shared/gfx/image.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
extern void __my_setcolor(int *ctset, int newcol, int wantColDep);
|
||||
|
||||
namespace AGS {
|
||||
namespace Shared {
|
||||
|
||||
Bitmap::Bitmap()
|
||||
: _alBitmap(nullptr)
|
||||
, _isDataOwner(false) {
|
||||
}
|
||||
|
||||
Bitmap::Bitmap(int width, int height, int color_depth)
|
||||
: _alBitmap(nullptr)
|
||||
, _isDataOwner(false) {
|
||||
Create(width, height, color_depth);
|
||||
}
|
||||
|
||||
Bitmap::Bitmap(Bitmap *src, const Rect &rc)
|
||||
: _alBitmap(nullptr)
|
||||
, _isDataOwner(false) {
|
||||
CreateSubBitmap(src, rc);
|
||||
}
|
||||
|
||||
Bitmap::Bitmap(BITMAP *al_bmp, bool shared_data)
|
||||
: _alBitmap(nullptr)
|
||||
, _isDataOwner(false) {
|
||||
WrapAllegroBitmap(al_bmp, shared_data);
|
||||
}
|
||||
|
||||
Bitmap::~Bitmap() {
|
||||
Destroy();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Creation and destruction
|
||||
//=============================================================================
|
||||
|
||||
bool Bitmap::Create(int width, int height, int color_depth) {
|
||||
Destroy();
|
||||
if (color_depth) {
|
||||
_alBitmap = create_bitmap_ex(color_depth, width, height);
|
||||
} else {
|
||||
_alBitmap = create_bitmap(width, height);
|
||||
}
|
||||
_isDataOwner = true;
|
||||
return _alBitmap != nullptr;
|
||||
}
|
||||
|
||||
bool Bitmap::CreateTransparent(int width, int height, int color_depth) {
|
||||
if (Create(width, height, color_depth)) {
|
||||
clear_to_color(_alBitmap, bitmap_mask_color(_alBitmap));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Bitmap::CreateSubBitmap(Bitmap *src, const Rect &rc) {
|
||||
Destroy();
|
||||
_alBitmap = create_sub_bitmap(src->_alBitmap, rc.Left, rc.Top, rc.GetWidth(), rc.GetHeight());
|
||||
_isDataOwner = true;
|
||||
return _alBitmap != nullptr;
|
||||
}
|
||||
|
||||
bool Bitmap::ResizeSubBitmap(int width, int height) {
|
||||
if (!isSubBitmap())
|
||||
return false;
|
||||
// TODO: can't clamp to parent size, because subs do not keep parent ref;
|
||||
// might require amending allegro bitmap struct
|
||||
_alBitmap->w = _alBitmap->cr = width;
|
||||
_alBitmap->h = _alBitmap->cb = height;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Bitmap::CreateCopy(Bitmap *src, int color_depth) {
|
||||
if (Create(src->_alBitmap->w, src->_alBitmap->h, color_depth ? color_depth : bitmap_color_depth(src->_alBitmap))) {
|
||||
blit(src->_alBitmap, _alBitmap, 0, 0, 0, 0, _alBitmap->w, _alBitmap->h);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Bitmap::WrapAllegroBitmap(BITMAP *al_bmp, bool shared_data) {
|
||||
Destroy();
|
||||
_alBitmap = al_bmp;
|
||||
_isDataOwner = !shared_data;
|
||||
return _alBitmap != nullptr;
|
||||
}
|
||||
|
||||
void Bitmap::Destroy() {
|
||||
if (_isDataOwner && _alBitmap) {
|
||||
destroy_bitmap(_alBitmap);
|
||||
}
|
||||
_alBitmap = nullptr;
|
||||
_isDataOwner = false;
|
||||
}
|
||||
|
||||
bool Bitmap::LoadFromFile(const char *filename) {
|
||||
Destroy();
|
||||
|
||||
BITMAP *al_bmp = load_bitmap(filename, nullptr);
|
||||
if (al_bmp) {
|
||||
_alBitmap = al_bmp;
|
||||
_isDataOwner = true;
|
||||
}
|
||||
return _alBitmap != nullptr;
|
||||
}
|
||||
|
||||
bool Bitmap::LoadFromFile(PACKFILE *pf) {
|
||||
Destroy();
|
||||
|
||||
BITMAP *al_bmp = load_bitmap(pf, nullptr);
|
||||
if (al_bmp) {
|
||||
_alBitmap = al_bmp;
|
||||
_isDataOwner = true;
|
||||
}
|
||||
return _alBitmap != nullptr;
|
||||
}
|
||||
|
||||
bool Bitmap::SaveToFile(Common::WriteStream &out, const void *palette) {
|
||||
return save_bitmap(out, _alBitmap, (const RGB *)palette);
|
||||
}
|
||||
|
||||
bool Bitmap::SaveToFile(const char *filename, const void *palette) {
|
||||
// Only keeps the file name and add the game target as prefix.
|
||||
Common::String name = filename;
|
||||
size_t lastSlash = name.findLastOf('/');
|
||||
if (lastSlash != Common::String::npos)
|
||||
name = name.substr(lastSlash + 1);
|
||||
Common::String gameTarget = ConfMan.getActiveDomainName();
|
||||
if (!name.hasPrefixIgnoreCase(gameTarget))
|
||||
name = gameTarget + "-" + name;
|
||||
|
||||
Common::OutSaveFile *out = g_system->getSavefileManager()->openForSaving(name, false);
|
||||
assert(out);
|
||||
bool result = SaveToFile(*out, palette);
|
||||
out->finalize();
|
||||
delete out;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
color_t Bitmap::GetCompatibleColor(color_t color) {
|
||||
color_t compat_color = 0;
|
||||
__my_setcolor(&compat_color, color, bitmap_color_depth(_alBitmap));
|
||||
return compat_color;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Clipping
|
||||
//=============================================================================
|
||||
|
||||
void Bitmap::SetClip(const Rect &rc) {
|
||||
set_clip_rect(_alBitmap, rc.Left, rc.Top, rc.Right, rc.Bottom);
|
||||
}
|
||||
|
||||
void Bitmap::ResetClip() {
|
||||
set_clip_rect(_alBitmap, 0, 0, _alBitmap->w - 1, _alBitmap->h - 1);
|
||||
}
|
||||
|
||||
Rect Bitmap::GetClip() const {
|
||||
Rect temp;
|
||||
get_clip_rect(_alBitmap, &temp.Left, &temp.Top, &temp.Right, &temp.Bottom);
|
||||
return temp;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Blitting operations (drawing one bitmap over another)
|
||||
//=============================================================================
|
||||
|
||||
void Bitmap::Blit(Bitmap *src, int dst_x, int dst_y, BitmapMaskOption mask) {
|
||||
BITMAP *al_src_bmp = src->_alBitmap;
|
||||
// WARNING: For some evil reason Allegro expects dest and src bitmaps in different order for blit and draw_sprite
|
||||
if (mask == kBitmap_Transparency) {
|
||||
draw_sprite(_alBitmap, al_src_bmp, dst_x, dst_y);
|
||||
} else {
|
||||
blit(al_src_bmp, _alBitmap, 0, 0, dst_x, dst_y, al_src_bmp->w, al_src_bmp->h);
|
||||
}
|
||||
}
|
||||
|
||||
void Bitmap::Blit(Bitmap *src, int src_x, int src_y, int dst_x, int dst_y, int width, int height, BitmapMaskOption mask) {
|
||||
BITMAP *al_src_bmp = src->_alBitmap;
|
||||
if (mask == kBitmap_Transparency) {
|
||||
masked_blit(al_src_bmp, _alBitmap, src_x, src_y, dst_x, dst_y, width, height);
|
||||
} else {
|
||||
blit(al_src_bmp, _alBitmap, src_x, src_y, dst_x, dst_y, width, height);
|
||||
}
|
||||
}
|
||||
|
||||
void Bitmap::MaskedBlit(Bitmap *src, int dst_x, int dst_y) {
|
||||
draw_sprite(_alBitmap, src->_alBitmap, dst_x, dst_y);
|
||||
}
|
||||
|
||||
void Bitmap::StretchBlt(Bitmap *src, const Rect &dst_rc, BitmapMaskOption mask) {
|
||||
BITMAP *al_src_bmp = src->_alBitmap;
|
||||
// WARNING: For some evil reason Allegro expects dest and src bitmaps in different order for blit and draw_sprite
|
||||
if (mask == kBitmap_Transparency) {
|
||||
stretch_sprite(_alBitmap, al_src_bmp,
|
||||
dst_rc.Left, dst_rc.Top, dst_rc.GetWidth(), dst_rc.GetHeight());
|
||||
} else {
|
||||
stretch_blit(al_src_bmp, _alBitmap,
|
||||
0, 0, al_src_bmp->w, al_src_bmp->h,
|
||||
dst_rc.Left, dst_rc.Top, dst_rc.GetWidth(), dst_rc.GetHeight());
|
||||
}
|
||||
}
|
||||
|
||||
void Bitmap::StretchBlt(Bitmap *src, const Rect &src_rc, const Rect &dst_rc, BitmapMaskOption mask) {
|
||||
BITMAP *al_src_bmp = src->_alBitmap;
|
||||
if (mask == kBitmap_Transparency) {
|
||||
masked_stretch_blit(al_src_bmp, _alBitmap,
|
||||
src_rc.Left, src_rc.Top, src_rc.GetWidth(), src_rc.GetHeight(),
|
||||
dst_rc.Left, dst_rc.Top, dst_rc.GetWidth(), dst_rc.GetHeight());
|
||||
} else {
|
||||
stretch_blit(al_src_bmp, _alBitmap,
|
||||
src_rc.Left, src_rc.Top, src_rc.GetWidth(), src_rc.GetHeight(),
|
||||
dst_rc.Left, dst_rc.Top, dst_rc.GetWidth(), dst_rc.GetHeight());
|
||||
}
|
||||
}
|
||||
|
||||
void Bitmap::AAStretchBlt(Bitmap *src, const Rect &dst_rc, BitmapMaskOption mask) {
|
||||
BITMAP *al_src_bmp = src->_alBitmap;
|
||||
// WARNING: For some evil reason Allegro expects dest and src bitmaps in different order for blit and draw_sprite
|
||||
if (mask == kBitmap_Transparency) {
|
||||
aa_stretch_sprite(_alBitmap, al_src_bmp,
|
||||
dst_rc.Left, dst_rc.Top, dst_rc.GetWidth(), dst_rc.GetHeight());
|
||||
} else {
|
||||
aa_stretch_blit(al_src_bmp, _alBitmap,
|
||||
0, 0, al_src_bmp->w, al_src_bmp->h,
|
||||
dst_rc.Left, dst_rc.Top, dst_rc.GetWidth(), dst_rc.GetHeight());
|
||||
}
|
||||
}
|
||||
|
||||
void Bitmap::AAStretchBlt(Bitmap *src, const Rect &src_rc, const Rect &dst_rc, BitmapMaskOption mask) {
|
||||
BITMAP *al_src_bmp = src->_alBitmap;
|
||||
if (mask == kBitmap_Transparency) {
|
||||
// TODO: aastr lib does not expose method for masked stretch blit; should do that at some point since
|
||||
// the source code is a gift-ware anyway
|
||||
// aa_masked_blit(_alBitmap, al_src_bmp, src_rc.Left, src_rc.Top, src_rc.GetWidth(), src_rc.GetHeight(), dst_rc.Left, dst_rc.Top, dst_rc.GetWidth(), dst_rc.GetHeight());
|
||||
error("aa_masked_blit is not yet supported!");
|
||||
} else {
|
||||
aa_stretch_blit(al_src_bmp, _alBitmap,
|
||||
src_rc.Left, src_rc.Top, src_rc.GetWidth(), src_rc.GetHeight(),
|
||||
dst_rc.Left, dst_rc.Top, dst_rc.GetWidth(), dst_rc.GetHeight());
|
||||
}
|
||||
}
|
||||
|
||||
void Bitmap::TransBlendBlt(Bitmap *src, int dst_x, int dst_y) {
|
||||
BITMAP *al_src_bmp = src->_alBitmap;
|
||||
draw_trans_sprite(_alBitmap, al_src_bmp, dst_x, dst_y);
|
||||
}
|
||||
|
||||
void Bitmap::LitBlendBlt(Bitmap *src, int dst_x, int dst_y, int light_amount) {
|
||||
BITMAP *al_src_bmp = src->_alBitmap;
|
||||
draw_lit_sprite(_alBitmap, al_src_bmp, dst_x, dst_y, light_amount);
|
||||
}
|
||||
|
||||
void Bitmap::FlipBlt(Bitmap *src, int dst_x, int dst_y, GraphicFlip flip) {
|
||||
BITMAP *al_src_bmp = src->_alBitmap;
|
||||
switch (flip) {
|
||||
case kFlip_Horizontal:
|
||||
draw_sprite_h_flip(_alBitmap, al_src_bmp, dst_x, dst_y);
|
||||
break;
|
||||
case kFlip_Vertical:
|
||||
draw_sprite_v_flip(_alBitmap, al_src_bmp, dst_x, dst_y);
|
||||
break;
|
||||
case kFlip_Both:
|
||||
draw_sprite_vh_flip(_alBitmap, al_src_bmp, dst_x, dst_y);
|
||||
break;
|
||||
default: // blit with no transform
|
||||
Blit(src, dst_x, dst_y);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Bitmap::RotateBlt(Bitmap *src, int dst_x, int dst_y, fixed_t angle) {
|
||||
BITMAP *al_src_bmp = src->_alBitmap;
|
||||
rotate_sprite(_alBitmap, al_src_bmp, dst_x, dst_y, angle);
|
||||
}
|
||||
|
||||
void Bitmap::RotateBlt(Bitmap *src, int dst_x, int dst_y, int pivot_x, int pivot_y, fixed_t angle) {
|
||||
BITMAP *al_src_bmp = src->_alBitmap;
|
||||
pivot_sprite(_alBitmap, al_src_bmp, dst_x, dst_y, pivot_x, pivot_y, angle);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Pixel operations
|
||||
//=============================================================================
|
||||
|
||||
void Bitmap::Clear(color_t color) {
|
||||
if (color) {
|
||||
clear_to_color(_alBitmap, color);
|
||||
} else {
|
||||
clear_bitmap(_alBitmap);
|
||||
}
|
||||
}
|
||||
|
||||
void Bitmap::ClearTransparent() {
|
||||
clear_to_color(_alBitmap, bitmap_mask_color(_alBitmap));
|
||||
}
|
||||
|
||||
void Bitmap::PutPixel(int x, int y, color_t color) {
|
||||
if (x < 0 || x >= _alBitmap->w || y < 0 || y >= _alBitmap->h) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (bitmap_color_depth(_alBitmap)) {
|
||||
case 8:
|
||||
return _putpixel(_alBitmap, x, y, color);
|
||||
case 15:
|
||||
return _putpixel15(_alBitmap, x, y, color);
|
||||
case 16:
|
||||
return _putpixel16(_alBitmap, x, y, color);
|
||||
case 24:
|
||||
return _putpixel24(_alBitmap, x, y, color);
|
||||
case 32:
|
||||
return _putpixel32(_alBitmap, x, y, color);
|
||||
}
|
||||
assert(0); // this should not normally happen
|
||||
return putpixel(_alBitmap, x, y, color);
|
||||
}
|
||||
|
||||
int Bitmap::GetPixel(int x, int y) const {
|
||||
if (x < 0 || x >= _alBitmap->w || y < 0 || y >= _alBitmap->h) {
|
||||
return -1; // Allegros getpixel() implementation returns -1 in this case
|
||||
}
|
||||
|
||||
switch (bitmap_color_depth(_alBitmap)) {
|
||||
case 8:
|
||||
return _getpixel(_alBitmap, x, y);
|
||||
case 15:
|
||||
return _getpixel15(_alBitmap, x, y);
|
||||
case 16:
|
||||
return _getpixel16(_alBitmap, x, y);
|
||||
case 24:
|
||||
return _getpixel24(_alBitmap, x, y);
|
||||
case 32:
|
||||
return _getpixel32(_alBitmap, x, y);
|
||||
}
|
||||
assert(0); // this should not normally happen
|
||||
return getpixel(_alBitmap, x, y);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Vector drawing operations
|
||||
//=============================================================================
|
||||
|
||||
void Bitmap::DrawLine(const Line &ln, color_t color) {
|
||||
line(_alBitmap, ln.X1, ln.Y1, ln.X2, ln.Y2, color);
|
||||
}
|
||||
|
||||
void Bitmap::DrawTriangle(const Triangle &tr, color_t color) {
|
||||
triangle(_alBitmap,
|
||||
tr.X1, tr.Y1, tr.X2, tr.Y2, tr.X3, tr.Y3, color);
|
||||
}
|
||||
|
||||
void Bitmap::DrawRect(const Rect &rc, color_t color) {
|
||||
rect(_alBitmap, rc.Left, rc.Top, rc.Right, rc.Bottom, color);
|
||||
}
|
||||
|
||||
void Bitmap::FillRect(const Rect &rc, color_t color) {
|
||||
rectfill(_alBitmap, rc.Left, rc.Top, rc.Right, rc.Bottom, color);
|
||||
}
|
||||
|
||||
void Bitmap::FillCircle(const Circle &circle, color_t color) {
|
||||
circlefill(_alBitmap, circle.X, circle.Y, circle.Radius, color);
|
||||
}
|
||||
|
||||
void Bitmap::Fill(color_t color) {
|
||||
if (color) {
|
||||
clear_to_color(_alBitmap, color);
|
||||
} else {
|
||||
clear_bitmap(_alBitmap);
|
||||
}
|
||||
}
|
||||
|
||||
void Bitmap::FillTransparent() {
|
||||
clear_to_color(_alBitmap, bitmap_mask_color(_alBitmap));
|
||||
}
|
||||
|
||||
void Bitmap::FloodFill(int x, int y, color_t color) {
|
||||
_alBitmap->floodfill(x, y, color);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Direct access operations
|
||||
//=============================================================================
|
||||
|
||||
void Bitmap::SetScanLine(int index, unsigned char *data, int data_size) {
|
||||
if (index < 0 || index >= GetHeight()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int copy_length = data_size;
|
||||
if (copy_length < 0) {
|
||||
copy_length = GetLineLength();
|
||||
} else // TODO: use Math namespace here
|
||||
if (copy_length > GetLineLength()) {
|
||||
copy_length = GetLineLength();
|
||||
}
|
||||
|
||||
memcpy(_alBitmap->line[index], data, copy_length);
|
||||
}
|
||||
|
||||
namespace BitmapHelper {
|
||||
|
||||
Bitmap *CreateRawBitmapOwner(BITMAP *al_bmp) {
|
||||
Bitmap *bitmap = new Bitmap();
|
||||
if (!bitmap->WrapAllegroBitmap(al_bmp, false)) {
|
||||
delete bitmap;
|
||||
bitmap = nullptr;
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
Bitmap *CreateRawBitmapWrapper(BITMAP *al_bmp) {
|
||||
Bitmap *bitmap = new Bitmap();
|
||||
if (!bitmap->WrapAllegroBitmap(al_bmp, true)) {
|
||||
delete bitmap;
|
||||
bitmap = nullptr;
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
} // namespace BitmapHelper
|
||||
|
||||
|
||||
} // namespace Shared
|
||||
} // namespace AGS
|
||||
} // namespace AGS3
|
||||
277
engines/ags/shared/gfx/allegro_bitmap.h
Normal file
277
engines/ags/shared/gfx/allegro_bitmap.h
Normal file
@@ -0,0 +1,277 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Allegro lib based bitmap
|
||||
//
|
||||
// TODO: probably should be moved to the Engine; check again when (if) it is
|
||||
// clear that AGS.Native does not need allegro for drawing.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef AGS_SHARED_GFX_ALLEGRO_BITMAP_H
|
||||
#define AGS_SHARED_GFX_ALLEGRO_BITMAP_H
|
||||
|
||||
#include "graphics/screen.h"
|
||||
#include "ags/lib/allegro.h" // BITMAP
|
||||
#include "ags/shared/core/types.h"
|
||||
#include "ags/shared/gfx/bitmap.h"
|
||||
#include "ags/shared/util/string.h"
|
||||
|
||||
namespace AGS3 {
|
||||
namespace AGS {
|
||||
namespace Shared {
|
||||
|
||||
class Bitmap {
|
||||
public:
|
||||
Bitmap();
|
||||
Bitmap(int width, int height, int color_depth = 0);
|
||||
Bitmap(Bitmap *src, const Rect &rc);
|
||||
Bitmap(BITMAP *al_bmp, bool shared_data);
|
||||
~Bitmap();
|
||||
|
||||
// Allocate new bitmap.
|
||||
// NOTE: color_depth is in BITS per pixel (i.e. 8, 16, 24, 32...).
|
||||
// NOTE: in all of these color_depth may be passed as 0 in which case a default
|
||||
// color depth will be used (as previously set for the system).
|
||||
// TODO: color_depth = 0 is used to call Allegro's create_bitmap, which uses
|
||||
// some global color depth setting; not sure if this is OK to use for generic class,
|
||||
// revise this in future
|
||||
bool Create(int width, int height, int color_depth = 0);
|
||||
// Create Bitmap and clear to transparent color
|
||||
bool CreateTransparent(int width, int height, int color_depth = 0);
|
||||
// Creates a sub-bitmap of the given bitmap; the sub-bitmap is a reference to
|
||||
// particular region inside a parent.
|
||||
// WARNING: the parent bitmap MUST be kept in memory for as long as sub-bitmap exists!
|
||||
bool CreateSubBitmap(Bitmap *src, const Rect &rc);
|
||||
// Resizes existing sub-bitmap within the borders of its parent
|
||||
bool ResizeSubBitmap(int width, int height);
|
||||
// Creates a plain copy of the given bitmap, optionally converting to a different color depth;
|
||||
// pass color depth 0 to keep the original one.
|
||||
bool CreateCopy(Bitmap *src, int color_depth = 0);
|
||||
// TODO: this is a temporary solution for plugin support
|
||||
// Wraps a raw allegro BITMAP object, optionally owns it (will delete on disposal)
|
||||
bool WrapAllegroBitmap(BITMAP *al_bmp, bool shared_data);
|
||||
// Deallocate bitmap
|
||||
void Destroy();
|
||||
|
||||
bool LoadFromFile(const String &filename) {
|
||||
return LoadFromFile(filename.GetCStr());
|
||||
}
|
||||
bool LoadFromFile(const char *filename);
|
||||
bool LoadFromFile(PACKFILE *pf);
|
||||
bool SaveToFile(const String &filename, const void *palette) {
|
||||
return SaveToFile(filename.GetCStr(), palette);
|
||||
}
|
||||
bool SaveToFile(Common::WriteStream &out, const void *palette);
|
||||
bool SaveToFile(const char *filename, const void *palette);
|
||||
|
||||
// TODO: This is temporary solution for cases when we cannot replace
|
||||
// use of raw BITMAP struct with Bitmap
|
||||
inline BITMAP *GetAllegroBitmap() {
|
||||
return _alBitmap;
|
||||
}
|
||||
|
||||
// Is this a "normal" bitmap created by application which data can be directly accessed for reading and writing
|
||||
inline bool IsMemoryBitmap() const {
|
||||
return true;
|
||||
}
|
||||
// Is this a video bitmap
|
||||
inline bool IsVideoBitmap() const {
|
||||
return dynamic_cast<Graphics::Screen *>(_alBitmap) != nullptr;
|
||||
}
|
||||
// Is this a linear bitmap, the one that can be accessed linearly within each scanline
|
||||
inline bool IsLinearBitmap() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Is this a subbitmap, referencing a part of another, bigger one?
|
||||
inline bool isSubBitmap() const {
|
||||
return _alBitmap->isSubBitmap();
|
||||
}
|
||||
|
||||
// Do both bitmaps share same data (usually: subbitmaps, or parent/subbitmap)
|
||||
inline bool IsSameBitmap(Bitmap *other) const {
|
||||
return is_same_bitmap(_alBitmap, other->_alBitmap) != 0;
|
||||
}
|
||||
|
||||
// Checks if bitmap cannot be used
|
||||
inline bool IsNull() const {
|
||||
return !_alBitmap;
|
||||
}
|
||||
// Checks if bitmap has zero size: either width or height (or both) is zero
|
||||
inline bool IsEmpty() const {
|
||||
return GetWidth() == 0 || GetHeight() == 0;
|
||||
}
|
||||
inline int GetWidth() const {
|
||||
return _alBitmap->w;
|
||||
}
|
||||
inline int GetHeight() const {
|
||||
return _alBitmap->h;
|
||||
}
|
||||
inline Size GetSize() const {
|
||||
return Size(_alBitmap->w, _alBitmap->h);
|
||||
}
|
||||
// Get sub-bitmap's offset position within its parent
|
||||
inline Point GetSubOffset() const {
|
||||
Common::Point pt = _alBitmap->getOffsetFromOwner();
|
||||
return Point(pt.x, pt.y);
|
||||
}
|
||||
inline int GetColorDepth() const {
|
||||
return bitmap_color_depth(_alBitmap);
|
||||
}
|
||||
// BPP: bytes per pixel
|
||||
inline int GetBPP() const {
|
||||
return (GetColorDepth() + 7) / 8;
|
||||
}
|
||||
|
||||
// CHECKME: probably should not be exposed, see comment to GetData()
|
||||
inline int GetDataSize() const {
|
||||
return GetWidth() * GetHeight() * GetBPP();
|
||||
}
|
||||
// Gets scanline length in bytes (is the same for any scanline)
|
||||
inline int GetLineLength() const {
|
||||
return GetWidth() * GetBPP();
|
||||
}
|
||||
|
||||
// TODO: replace with byte *
|
||||
// Gets a pointer to underlying graphic data
|
||||
// FIXME: actually not a very good idea, since there's no 100% guarantee the scanline positions in memory are sequential
|
||||
inline const unsigned char *GetData() const {
|
||||
return _alBitmap->getPixels();
|
||||
}
|
||||
|
||||
// Get scanline for direct reading
|
||||
inline const unsigned char *GetScanLine(int index) const {
|
||||
assert(index >= 0 && index < GetHeight());
|
||||
return _alBitmap->getBasePtr(0, index);
|
||||
}
|
||||
inline unsigned char *GetScanLine(int index) {
|
||||
assert(index >= 0 && index < GetHeight());
|
||||
return (unsigned char *)_alBitmap->getBasePtr(0, index);
|
||||
}
|
||||
|
||||
// Get bitmap's mask color (transparent color)
|
||||
inline color_t GetMaskColor() const {
|
||||
return bitmap_mask_color(_alBitmap);
|
||||
}
|
||||
|
||||
// Converts AGS color-index into RGB color according to the bitmap format.
|
||||
// TODO: this method was added to the Bitmap class during large refactoring,
|
||||
// but that's a mistake, because in retrospect is has nothing to do with
|
||||
// bitmap itself and should rather be a part of the game data logic.
|
||||
color_t GetCompatibleColor(color_t color);
|
||||
|
||||
//=========================================================================
|
||||
// Clipping
|
||||
// TODO: consider implementing push-pop clipping stack logic.
|
||||
//=========================================================================
|
||||
void SetClip(const Rect &rc);
|
||||
void ResetClip();
|
||||
Rect GetClip() const;
|
||||
|
||||
//=========================================================================
|
||||
// Blitting operations (drawing one bitmap over another)
|
||||
//=========================================================================
|
||||
// Draw other bitmap over current one
|
||||
void Blit(Bitmap *src, int dst_x = 0, int dst_y = 0, BitmapMaskOption mask = kBitmap_Copy);
|
||||
void Blit(Bitmap *src, int src_x, int src_y, int dst_x, int dst_y, int width, int height, BitmapMaskOption mask = kBitmap_Copy);
|
||||
// Draw other bitmap in a masked mode (kBitmap_Transparency)
|
||||
void MaskedBlit(Bitmap *src, int dst_x, int dst_y);
|
||||
// Draw other bitmap, stretching or shrinking its size to given values
|
||||
void StretchBlt(Bitmap *src, const Rect &dst_rc, BitmapMaskOption mask = kBitmap_Copy);
|
||||
void StretchBlt(Bitmap *src, const Rect &src_rc, const Rect &dst_rc, BitmapMaskOption mask = kBitmap_Copy);
|
||||
// Antia-aliased stretch-blit
|
||||
void AAStretchBlt(Bitmap *src, const Rect &dst_rc, BitmapMaskOption mask = kBitmap_Copy);
|
||||
void AAStretchBlt(Bitmap *src, const Rect &src_rc, const Rect &dst_rc, BitmapMaskOption mask = kBitmap_Copy);
|
||||
// TODO: find more general way to call these operations, probably require pointer to Blending data struct?
|
||||
// Draw bitmap using translucency preset
|
||||
void TransBlendBlt(Bitmap *src, int dst_x, int dst_y);
|
||||
// Draw bitmap using lighting preset
|
||||
void LitBlendBlt(Bitmap *src, int dst_x, int dst_y, int light_amount);
|
||||
// TODO: generic "draw transformed" function? What about mask option?
|
||||
void FlipBlt(Bitmap *src, int dst_x, int dst_y, GraphicFlip flip);
|
||||
void RotateBlt(Bitmap *src, int dst_x, int dst_y, fixed_t angle);
|
||||
void RotateBlt(Bitmap *src, int dst_x, int dst_y, int pivot_x, int pivot_y, fixed_t angle);
|
||||
|
||||
//=========================================================================
|
||||
// Pixel operations
|
||||
//=========================================================================
|
||||
// Fills the whole bitmap with given color (black by default)
|
||||
void Clear(color_t color = 0);
|
||||
void ClearTransparent();
|
||||
// The PutPixel and GetPixel are supposed to be safe and therefore
|
||||
// relatively slow operations. They should not be used for changing large
|
||||
// blocks of bitmap memory - reading/writing from/to scan lines should be
|
||||
// done in such cases.
|
||||
void PutPixel(int x, int y, color_t color);
|
||||
int GetPixel(int x, int y) const;
|
||||
|
||||
//=========================================================================
|
||||
// Vector drawing operations
|
||||
//=========================================================================
|
||||
void DrawLine(const Line &ln, color_t color);
|
||||
void DrawTriangle(const Triangle &tr, color_t color);
|
||||
void DrawRect(const Rect &rc, color_t color);
|
||||
void FillRect(const Rect &rc, color_t color);
|
||||
void FillCircle(const Circle &circle, color_t color);
|
||||
// Fills the whole bitmap with given color
|
||||
void Fill(color_t color);
|
||||
void FillTransparent();
|
||||
// Floodfills an enclosed area, starting at point
|
||||
void FloodFill(int x, int y, color_t color);
|
||||
|
||||
//=========================================================================
|
||||
// Direct access operations
|
||||
//=========================================================================
|
||||
// TODO: think how to increase safety over this (some fixed memory buffer class with iterator?)
|
||||
// Gets scanline for directly writing into it
|
||||
inline unsigned char *GetScanLineForWriting(int index) {
|
||||
assert(index >= 0 && index < GetHeight());
|
||||
return _alBitmap->line[index];
|
||||
}
|
||||
inline unsigned char *GetDataForWriting() {
|
||||
return _alBitmap->line[0];
|
||||
}
|
||||
// Copies buffer contents into scanline
|
||||
void SetScanLine(int index, unsigned char *data, int data_size = -1);
|
||||
|
||||
private:
|
||||
BITMAP *_alBitmap;
|
||||
bool _isDataOwner;
|
||||
};
|
||||
|
||||
|
||||
|
||||
namespace BitmapHelper {
|
||||
// TODO: revise those functions later (currently needed in a few very specific cases)
|
||||
// NOTE: the resulting object __owns__ bitmap data from now on
|
||||
Bitmap *CreateRawBitmapOwner(BITMAP *al_bmp);
|
||||
// NOTE: the resulting object __does not own__ bitmap data
|
||||
Bitmap *CreateRawBitmapWrapper(BITMAP *al_bmp);
|
||||
} // namespace BitmapHelper
|
||||
|
||||
} // namespace Shared
|
||||
} // namespace AGS
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
240
engines/ags/shared/gfx/bitmap.cpp
Normal file
240
engines/ags/shared/gfx/bitmap.cpp
Normal file
@@ -0,0 +1,240 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#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<uint32_t *>(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<uint32_t *>(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<uint32_t *>(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 <class TPx, size_t BPP_>
|
||||
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<uint8_t, 1> PixelTransCpy8;
|
||||
typedef PixelTransCpy<uint16_t, 2> 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 <class FnPxProc, class FnSkip>
|
||||
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
|
||||
114
engines/ags/shared/gfx/bitmap.h
Normal file
114
engines/ags/shared/gfx/bitmap.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Base bitmap header
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef AGS_SHARED_GFX_BITMAP_H
|
||||
#define AGS_SHARED_GFX_BITMAP_H
|
||||
|
||||
#include "ags/shared/gfx/gfx_def.h"
|
||||
#include "ags/shared/util/geometry.h"
|
||||
#include "ags/shared/util/string.h"
|
||||
|
||||
namespace AGS3 {
|
||||
namespace AGS {
|
||||
namespace Shared {
|
||||
|
||||
// Mask option for blitting one bitmap on another
|
||||
enum BitmapMaskOption {
|
||||
// Plain copies bitmap pixels
|
||||
kBitmap_Copy,
|
||||
// Consider mask color fully transparent and do not copy pixels having it
|
||||
kBitmap_Transparency
|
||||
};
|
||||
|
||||
} // namespace Shared
|
||||
} // namespace AGS
|
||||
} // namespace AGS3
|
||||
|
||||
#include "ags/shared/gfx/allegro_bitmap.h"
|
||||
|
||||
namespace AGS3 {
|
||||
namespace AGS {
|
||||
namespace Shared {
|
||||
|
||||
class Bitmap;
|
||||
|
||||
// TODO: revise this construction later
|
||||
namespace BitmapHelper {
|
||||
|
||||
// Helper functions, that delete faulty bitmaps automatically, and return
|
||||
// NULL if bitmap could not be created.
|
||||
// NOTE: color_depth is in BITS per pixel (i.e. 8, 16, 24, 32...).
|
||||
// NOTE: in all of these color_depth may be passed as 0 in which case a default
|
||||
// color depth will be used (as previously set for the system).
|
||||
// Creates a new bitmap of the given format; the pixel contents are undefined.
|
||||
Bitmap *CreateBitmap(int width, int height, int color_depth = 0);
|
||||
// Creates a new bitmap and clears it with the given color
|
||||
Bitmap *CreateClearBitmap(int width, int height, int color_depth = 0, int clear_color = 0);
|
||||
// Creates a new bitmap and clears it with the transparent color
|
||||
Bitmap *CreateTransparentBitmap(int width, int height, int color_depth = 0);
|
||||
// Creates a sub-bitmap of the given bitmap; the sub-bitmap is a reference to
|
||||
// particular region inside a parent.
|
||||
// WARNING: the parent bitmap MUST be kept in memory for as long as sub-bitmap exists!
|
||||
Bitmap *CreateSubBitmap(Bitmap *src, const Rect &rc);
|
||||
// Creates a plain copy of the given bitmap, optionally converting to a different color depth;
|
||||
// pass color depth 0 to keep the original one.
|
||||
Bitmap *CreateBitmapCopy(Bitmap *src, int color_depth = 0);
|
||||
|
||||
// Load a bitmap from file; supported formats currently are: BMP, PCX.
|
||||
Bitmap *LoadFromFile(const char *filename);
|
||||
inline Bitmap *LoadFromFile(const String &filename) {
|
||||
return LoadFromFile(filename.GetCStr());
|
||||
}
|
||||
Bitmap *LoadFromFile(PACKFILE *pf);
|
||||
|
||||
// Stretches bitmap to the requested size. The new bitmap will have same
|
||||
// colour depth. Returns original bitmap if no changes are necessary.
|
||||
Bitmap *AdjustBitmapSize(Bitmap *src, int width, int height);
|
||||
// Makes the given bitmap opaque (full alpha), while keeping pixel RGB unchanged.
|
||||
void MakeOpaque(Bitmap *bmp);
|
||||
// Makes the given bitmap opaque (full alpha), while keeping pixel RGB unchanged.
|
||||
// Skips mask color (leaves it with zero alpha).
|
||||
void MakeOpaqueSkipMask(Bitmap *bmp);
|
||||
// Replaces fully transparent (alpha = 0) pixels with standard mask color.
|
||||
void ReplaceAlphaWithRGBMask(Bitmap *bmp);
|
||||
// Copy transparency mask and/or alpha channel from one bitmap into another.
|
||||
// Destination and mask bitmaps must be of the same pixel format.
|
||||
// Transparency is merged, meaning that fully transparent pixels on
|
||||
// destination should remain such regardless of mask pixel values.
|
||||
void CopyTransparency(Bitmap *dst, const Bitmap *mask, bool dst_has_alpha, bool mask_has_alpha);
|
||||
// Copy pixel data into bitmap from memory buffer. It is required that the
|
||||
// source matches bitmap format and has enough data.
|
||||
// Pitch is given in bytes and defines the length of the source scan line.
|
||||
// Offset is optional and defines horizontal offset, in pixels.
|
||||
void ReadPixelsFromMemory(Bitmap *dst, const uint8_t *src_buffer, const size_t src_pitch, const size_t src_px_offset = 0);
|
||||
|
||||
} // namespace BitmapHelper
|
||||
} // namespace Shared
|
||||
} // namespace AGS
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
152
engines/ags/shared/gfx/gfx_def.h
Normal file
152
engines/ags/shared/gfx/gfx_def.h
Normal file
@@ -0,0 +1,152 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//=============================================================================
|
||||
//
|
||||
// Graphic definitions and type/unit conversions.
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef AGS_SHARED_GFX_GFX_DEF_H
|
||||
#define AGS_SHARED_GFX_GFX_DEF_H
|
||||
|
||||
namespace AGS3 {
|
||||
namespace AGS {
|
||||
namespace Shared {
|
||||
|
||||
enum GraphicFlip {
|
||||
kFlip_None,
|
||||
kFlip_Horizontal, // this means - mirror over horizontal middle line
|
||||
kFlip_Vertical, // this means - mirror over vertical middle line
|
||||
kFlip_Both // mirror over diagonal (horizontal and vertical)
|
||||
};
|
||||
|
||||
enum BlendMode {
|
||||
// free blending (ARGB -> ARGB) modes
|
||||
kBlendMode_NoAlpha = 0, // ignore alpha channel
|
||||
kBlendMode_Alpha, // alpha-blend src to dest, combining src & dest alphas
|
||||
// NOTE: add new modes here
|
||||
|
||||
kNumBlendModes
|
||||
};
|
||||
|
||||
namespace GfxDef {
|
||||
|
||||
// Converts percentage of transparency into alpha
|
||||
inline int Trans100ToAlpha255(int transparency) {
|
||||
return ((100 - transparency) * 255) / 100;
|
||||
}
|
||||
|
||||
// Converts alpha into percentage of transparency
|
||||
inline int Alpha255ToTrans100(int alpha) {
|
||||
return 100 - ((alpha * 100) / 255);
|
||||
}
|
||||
|
||||
// Special formulae to reduce precision loss and support flawless forth &
|
||||
// reverse conversion for multiplies of 10%
|
||||
inline int Trans100ToAlpha250(int transparency) {
|
||||
return ((100 - transparency) * 25) / 10;
|
||||
}
|
||||
|
||||
inline int Alpha250ToTrans100(int alpha) {
|
||||
return 100 - ((alpha * 10) / 25);
|
||||
}
|
||||
|
||||
// Convert correct 100-ranged transparency into legacy 255-ranged
|
||||
// transparency; legacy inconsistent transparency value range:
|
||||
// 0 = opaque,
|
||||
// 255 = invisible,
|
||||
// 1 -to- 254 = barely visible -to- mostly visible (as proper alpha)
|
||||
inline int Trans100ToLegacyTrans255(int transparency) {
|
||||
switch (transparency) {
|
||||
case 0:
|
||||
return 0; // this means opaque
|
||||
case 100:
|
||||
return 255; // this means invisible
|
||||
default:
|
||||
// the rest of the range works as alpha
|
||||
return Trans100ToAlpha250(transparency);
|
||||
}
|
||||
}
|
||||
|
||||
// Convert legacy 255-ranged "incorrect" transparency into proper
|
||||
// 100-ranged transparency.
|
||||
inline int LegacyTrans255ToTrans100(int legacy_transparency) {
|
||||
switch (legacy_transparency) {
|
||||
case 0:
|
||||
return 0; // this means opaque
|
||||
case 255:
|
||||
return 100; // this means invisible
|
||||
default:
|
||||
// the rest of the range works as alpha
|
||||
return Alpha250ToTrans100(legacy_transparency);
|
||||
}
|
||||
}
|
||||
|
||||
// Convert legacy 100-ranged transparency into proper 255-ranged alpha
|
||||
// 0 => alpha 255
|
||||
// 100 => alpha 0
|
||||
// 1 - 99 => alpha 1 - 244
|
||||
inline int LegacyTrans100ToAlpha255(int legacy_transparency) {
|
||||
switch (legacy_transparency) {
|
||||
case 0:
|
||||
return 255; // this means opaque
|
||||
case 100:
|
||||
return 0; // this means invisible
|
||||
default:
|
||||
// the rest of the range works as alpha (only 100-ranged)
|
||||
return legacy_transparency * 255 / 100;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert legacy 255-ranged transparency into proper 255-ranged alpha
|
||||
inline int LegacyTrans255ToAlpha255(int legacy_transparency) {
|
||||
switch (legacy_transparency) {
|
||||
case 0:
|
||||
return 255; // this means opaque
|
||||
case 255:
|
||||
return 0; // this means invisible
|
||||
default:
|
||||
// the rest of the range works as alpha
|
||||
return legacy_transparency;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert 255-ranged alpha into legacy 255-ranged transparency
|
||||
inline int Alpha255ToLegacyTrans255(int alpha) {
|
||||
switch (alpha) {
|
||||
case 255:
|
||||
return 0; // this means opaque
|
||||
case 0:
|
||||
return 255; // this means invisible
|
||||
default:
|
||||
// the rest of the range works as alpha
|
||||
return alpha;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace GfxDef
|
||||
|
||||
} // namespace Shared
|
||||
} // namespace AGS
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
151
engines/ags/shared/gfx/image.cpp
Normal file
151
engines/ags/shared/gfx/image.cpp
Normal file
@@ -0,0 +1,151 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ags/shared/gfx/image.h"
|
||||
#include "ags/shared/util/file.h"
|
||||
#include "ags/shared/util/stream.h"
|
||||
#include "ags/lib/allegro.h"
|
||||
#include "common/file.h"
|
||||
#include "common/str.h"
|
||||
#include "common/stream.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "image/bmp.h"
|
||||
#include "image/iff.h"
|
||||
#include "image/pcx.h"
|
||||
#include "image/tga.h"
|
||||
|
||||
#define VGA_COLOR_TRANS(x) ((x) * 255 / 63)
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
template<class DECODER>
|
||||
BITMAP *decodeImageStream(Common::SeekableReadStream &stream, color *pal) {
|
||||
DECODER decoder;
|
||||
|
||||
if (decoder.loadStream(stream)) {
|
||||
// Create the output surface
|
||||
const Graphics::Surface *src = decoder.getSurface();
|
||||
|
||||
// Copy the decoded surface
|
||||
int bpp = 8 * src->format.bytesPerPixel;
|
||||
if (bpp == 24)
|
||||
bpp = 32;
|
||||
Surface *dest = (Surface *)create_bitmap_ex(bpp, src->w, src->h);
|
||||
dest->blitFrom(*src);
|
||||
|
||||
// Copy the palette
|
||||
const Graphics::Palette &palP = decoder.getPalette();
|
||||
if (pal) {
|
||||
for (uint idx = 0; idx < palP.size(); ++idx) {
|
||||
palP.get(idx, pal[idx].r, pal[idx].g, pal[idx].b);
|
||||
pal[idx].filler = 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
return dest;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template<class DECODER>
|
||||
BITMAP *decodeImage(const char *filename, color *pal) {
|
||||
AGS::Shared::Stream *file = AGS3::AGS::Shared::File::OpenFileRead(filename);
|
||||
if (!file)
|
||||
return nullptr;
|
||||
|
||||
AGS::Shared::ScummVMReadStream f(file);
|
||||
return decodeImageStream<DECODER>(f, pal);
|
||||
}
|
||||
|
||||
template<class DECODER>
|
||||
BITMAP *decodeImage(PACKFILE *pf, color *pal) {
|
||||
if (!pf)
|
||||
return nullptr;
|
||||
|
||||
AGS::Shared::ScummVMPackReadStream f(pf);
|
||||
f.seek(0);
|
||||
return decodeImageStream<DECODER>(f, pal);
|
||||
}
|
||||
|
||||
BITMAP *load_bmp(const char *filename, color *pal) {
|
||||
return decodeImage<Image::BitmapDecoder>(filename, pal);
|
||||
}
|
||||
|
||||
BITMAP *load_lbm(const char *filename, color *pal) {
|
||||
return decodeImage<Image::IFFDecoder>(filename, pal);
|
||||
}
|
||||
|
||||
BITMAP *load_pcx(const char *filename, color *pal) {
|
||||
return decodeImage<Image::PCXDecoder>(filename, pal);
|
||||
}
|
||||
|
||||
BITMAP *load_tga(const char *filename, color *pal) {
|
||||
return decodeImage<Image::TGADecoder>(filename, pal);
|
||||
}
|
||||
|
||||
BITMAP *load_bitmap(const char *filename, color *pal) {
|
||||
Common::String fname(filename);
|
||||
|
||||
if (fname.hasSuffixIgnoreCase(".bmp"))
|
||||
return load_bmp(filename, pal);
|
||||
else if (fname.hasSuffixIgnoreCase(".lbm"))
|
||||
return load_lbm(filename, pal);
|
||||
else if (fname.hasSuffixIgnoreCase(".pcx"))
|
||||
return load_pcx(filename, pal);
|
||||
else if (fname.hasSuffixIgnoreCase(".tga"))
|
||||
return load_tga(filename, pal);
|
||||
else
|
||||
error("Unknown image file - %s", filename);
|
||||
}
|
||||
|
||||
BITMAP *load_bitmap(PACKFILE *pf, color *pal) {
|
||||
BITMAP *result;
|
||||
|
||||
if ((result = decodeImage<Image::BitmapDecoder>(pf, pal)) != nullptr)
|
||||
return result;
|
||||
if ((result = decodeImage<Image::IFFDecoder>(pf, pal)) != nullptr)
|
||||
return result;
|
||||
if ((result = decodeImage<Image::PCXDecoder>(pf, pal)) != nullptr)
|
||||
return result;
|
||||
if ((result = decodeImage<Image::TGADecoder>(pf, pal)) != nullptr)
|
||||
return result;
|
||||
|
||||
error("Unknown image file");
|
||||
}
|
||||
|
||||
bool save_bitmap(Common::WriteStream &out, BITMAP *bmp, const RGB *pal) {
|
||||
const Graphics::ManagedSurface &src = bmp->getSurface();
|
||||
if (bmp->format.isCLUT8() && pal) {
|
||||
byte palette[256 * 3];
|
||||
for (int c = 0, i = 0; c < 256; ++c, i += 3) {
|
||||
palette[i] = VGA_COLOR_TRANS(pal[c].r);
|
||||
palette[i + 1] = VGA_COLOR_TRANS(pal[c].g);
|
||||
palette[i + 2] = VGA_COLOR_TRANS(pal[c].b);
|
||||
}
|
||||
|
||||
return Image::writeBMP(out, src, palette);
|
||||
} else {
|
||||
return Image::writeBMP(out, src);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace AGS
|
||||
42
engines/ags/shared/gfx/image.h
Normal file
42
engines/ags/shared/gfx/image.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/* 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 <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AGS_SHARED_GFX_IMAGE_H
|
||||
#define AGS_SHARED_GFX_IMAGE_H
|
||||
|
||||
#include "ags/lib/allegro.h"
|
||||
|
||||
namespace AGS3 {
|
||||
|
||||
struct PACKFILE;
|
||||
|
||||
extern BITMAP *load_bitmap(PACKFILE *pf, color *pal);
|
||||
extern BITMAP *load_bitmap(const char *filename, color *pal);
|
||||
extern BITMAP *load_bmp(const char *filename, color *pal);
|
||||
extern BITMAP *load_lbm(const char *filename, color *pal);
|
||||
extern BITMAP *load_pcx(const char *filename, color *pal);
|
||||
extern BITMAP *load_tga(const char *filename, color *pal);
|
||||
|
||||
extern bool save_bitmap(Common::WriteStream &out, BITMAP *bmp, const RGB *pal);
|
||||
|
||||
} // namespace AGS3
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user