ScummVM API documentation
surface.h
1/* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#ifndef AGS_LIB_ALLEGRO_SURFACE_H
23#define AGS_LIB_ALLEGRO_SURFACE_H
24
25#include "graphics/managed_surface.h"
26#include "ags/lib/allegro/base.h"
27#include "ags/lib/allegro/color.h"
28#include "common/array.h"
29
30namespace AGS3 {
31
32class BITMAP {
33private:
35 public:
36 int16 &w, &h;
37 int32 &pitch;
39 bool clip;
40 int ct, cb, cl, cr;
42public:
44 virtual ~BITMAP() {
45 }
46
47 Graphics::ManagedSurface &operator*() const {
48 return *_owner;
49 }
50 Graphics::ManagedSurface &getSurface() {
51 return *_owner;
52 }
53 const Graphics::ManagedSurface &getSurface() const {
54 return *_owner;
55 }
56
57 unsigned char *getPixels() const {
58 return (unsigned char *)_owner->getPixels();
59 }
60
61 unsigned char *getBasePtr(uint16 x, uint16 y) const {
62 return (unsigned char *)_owner->getBasePtr(x, y);
63 }
64
65 uint getTransparentColor() const {
66 // See allegro bitmap_mask_color
67 // For paletted sprites this is 0.
68 // For other color depths this is bright pink (RGB 255, 0, 255) with alpha set to 0.
69 if (format.bytesPerPixel == 1)
70 return 0;
71 return format.ARGBToColor(0, 255, 0, 255);
72 }
73
74 inline const Common::Point getOffsetFromOwner() const {
75 return _owner->getOffsetFromOwner();
76 }
77
78 int getpixel(int x, int y) const;
79
80 void clear() {
81 _owner->clear();
82 }
83
84 void makeOpaque();
85
89 void circlefill(int x, int y, int radius, int color);
90
94 void floodfill(int x, int y, int color);
95
99 void hLine(int x, int y, int x2, uint32 color) {
100 _owner->hLine(x, y, x2, color);
101 }
102
106 void vLine(int x, int y, int y2, uint32 color) {
107 _owner->vLine(x, y, y2, color);
108 }
109
113 void draw(const BITMAP *srcBitmap, const Common::Rect &srcRect,
114 int dstX, int dstY, bool horizFlip, bool vertFlip,
115 bool skipTrans, int srcAlpha, int tintRed = -1, int tintGreen = -1,
116 int tintBlue = -1);
117
121 void stretchDraw(const BITMAP *srcBitmap, const Common::Rect &srcRect,
122 const Common::Rect &destRect, bool skipTrans, int srcAlpha);
123
124 inline bool isSubBitmap() const {
125 return _owner->disposeAfterUse() == DisposeAfterUse::NO;
126 }
127
128 private:
129 // True color blender functions
130 // In Allegro all the blender functions are of the form
131 // unsigned int blender_func(unsigned long x, unsigned long y, unsigned long n)
132 // when x is the sprite color, y the destination color, and n an alpha value
133
134 void blendPixel(uint8 aSrc, uint8 rSrc, uint8 gSrc, uint8 bSrc, uint8 &aDest, uint8 &rDest, uint8 &gDest, uint8 &bDest, uint32 alpha, bool useTint, byte *destVal) const;
135
136 inline void rgbBlend(uint8 rSrc, uint8 gSrc, uint8 bSrc, uint8 &rDest, uint8 &gDest, uint8 &bDest, uint32 alpha) const {
137 // Note: the original's handling varies slightly for R & B vs G.
138 // We need to exactly replicate it to ensure Lamplight City's
139 // calendar puzzle works correctly
140 if (alpha)
141 alpha++;
142
143 uint32 x = ((uint32)rSrc << 16) | ((uint32)gSrc << 8) | (uint32)bSrc;
144 uint32 y = ((uint32)rDest << 16) | ((uint32)gDest << 8) | (uint32)bDest;
145
146 uint32 res = ((x & 0xFF00FF) - (y & 0xFF00FF)) * alpha / 256 + y;
147 y &= 0xFF00;
148 x &= 0xFF00;
149 uint32 g = (x - y) * alpha / 256 + y;
150
151 rDest = (res >> 16) & 0xff;
152 gDest = (g >> 8) & 0xff;
153 bDest = res & 0xff;
154 }
155
156 inline void argbBlend(uint32 aSrc, uint8 rSrc, uint8 gSrc, uint8 bSrc, uint8 &aDest, uint8 &rDest, uint8 &gDest, uint8 &bDest) const {
157 // Original logic has uint32 src and dst colors as ARGB8888
158 // ++src_alpha;
159 // uint32 dst_alpha = geta32(dst);
160 // if (dst_alpha)
161 // ++dst_alpha;
162 // uint32 dst_g = (dst & 0x00FF00) * dst_alpha / 256;
163 // dst = (dst & 0xFF00FF) * dst_alpha / 256;
164 // dst_g = (((src & 0x00FF00) - (dst_g & 0x00FF00)) * src_alpha / 256 + dst_g) & 0x00FF00;
165 // dst = (((src & 0xFF00FF) - (dst & 0xFF00FF)) * src_alpha / 256 + dst) & 0xFF00FF;
166 // dst_alpha = 256 - (256 - src_alpha) * (256 - dst_alpha) / 256;
167 // src_alpha = /* 256 * 256 == */ 0x10000 / dst_alpha;
168 // dst_g = (dst_g * src_alpha / 256) & 0x00FF00;
169 // dst = (dst * src_alpha / 256) & 0xFF00FF;
170 // return dst | dst_g | (--dst_alpha << 24);
171 double sAlpha = (double)(aSrc & 0xff) / 255.0;
172 double dAlpha = (double)aDest / 255.0;
173 dAlpha *= (1.0 - sAlpha);
174 rDest = static_cast<uint8>((rSrc * sAlpha + rDest * dAlpha) / (sAlpha + dAlpha));
175 gDest = static_cast<uint8>((gSrc * sAlpha + gDest * dAlpha) / (sAlpha + dAlpha));
176 bDest = static_cast<uint8>((bSrc * sAlpha + bDest * dAlpha) / (sAlpha + dAlpha));
177 aDest = static_cast<uint8>(255. * (sAlpha + dAlpha));
178 }
179
180 // kRgbToRgbBlender
181 inline void blendRgbToRgb(uint8 aSrc, uint8 rSrc, uint8 gSrc, uint8 bSrc, uint8 &aDest, uint8 &rDest, uint8 &gDest, uint8 &bDest, uint32 alpha) const {
182 // Default mode for set_trans_blender
183 rgbBlend(rSrc, gSrc, bSrc, rDest, gDest, bDest, alpha);
184 // Original doesn't set alpha (so it is 0), but the function is not meant to be used
185 // on bitmap with transparency. Should we set alpha to 0xff?
186 aDest = 0;
187 }
188
189 // kAlphaPreservedBlenderMode
190 inline void blendPreserveAlpha(uint8 aSrc, uint8 rSrc, uint8 gSrc, uint8 bSrc, uint8 &aDest, uint8 &rDest, uint8 &gDest, uint8 &bDest, uint32 alpha) const {
191 // Original blender function: _myblender_alpha_trans24
192 // Like blendRgbToRgb, but result as the same alpha as destColor
193 rgbBlend(rSrc, gSrc, bSrc, rDest, gDest, bDest, alpha);
194 // Preserve value in aDest
195 }
196
197 // kArgbToArgbBlender
198 inline void blendArgbToArgb(uint8 aSrc, uint8 rSrc, uint8 gSrc, uint8 bSrc, uint8 &aDest, uint8 &rDest, uint8 &gDest, uint8 &bDest, uint32 alpha) const {
199 // Original blender functions: _argb2argb_blender
200 if (alpha == 0)
201 alpha = aSrc;
202 else
203 alpha = aSrc * ((alpha & 0xff) + 1) / 256;
204 if (alpha != 0)
205 argbBlend(alpha, rSrc, gSrc, bSrc, aDest, rDest, gDest, bDest);
206 }
207
208 // kRgbToArgbBlender
209 inline void blendRgbToArgb(uint8 aSrc, uint8 rSrc, uint8 gSrc, uint8 bSrc, uint8 &aDest, uint8 &rDest, uint8 &gDest, uint8 &bDest, uint32 alpha) const {
210 // Original blender function: _rgb2argb_blenders
211 if (alpha == 0 || alpha == 0xff) {
212 aDest = 0xff;
213 rDest = rSrc;
214 gDest = gSrc;
215 bDest = bSrc;
216 } else
217 argbBlend(alpha, rSrc, gSrc, bSrc, aDest, rDest, gDest, bDest);
218 }
219
220 // kArgbToRgbBlender
221 inline void blendArgbToRgb(uint8 aSrc, uint8 rSrc, uint8 gSrc, uint8 bSrc, uint8 &aDest, uint8 &rDest, uint8 &gDest, uint8 &bDest, uint32 alpha) const {
222 // Original blender function: _argb2rgb_blender
223 if (alpha == 0)
224 alpha = aSrc;
225 else
226 alpha = aSrc * ((alpha & 0xff) + 1) / 256;
227 rgbBlend(rSrc, gSrc, bSrc, rDest, gDest, bDest, alpha);
228 // Original doesn't set alpha (so it is 0), but the function is not meant to be used
229 // on bitmap with transparency. Should we set alpha to 0xff?
230 aDest = 0;
231 }
232
233 // kOpaqueBlenderMode
234 inline void blendOpaque(uint8 aSrc, uint8 rSrc, uint8 gSrc, uint8 bSrc, uint8 &aDest, uint8 &rDest, uint8 &gDest, uint8 &bDest, uint32 alpha) const {
235 // Original blender function: _opaque_alpha_blender
236 aDest = 0xff;
237 rDest = rSrc;
238 gDest = gSrc;
239 bDest = bSrc;
240 }
241
242 // kSourceAlphaBlender
243 inline void blendSourceAlpha(uint8 aSrc, uint8 rSrc, uint8 gSrc, uint8 bSrc, uint8 &aDest, uint8 &rDest, uint8 &gDest, uint8 &bDest, uint32 alpha) const {
244 // Used after set_alpha_blender
245 // Uses alpha from source. Result is fully opaque
246 rgbBlend(rSrc, gSrc, bSrc, rDest, gDest, bDest, aSrc);
247 // Original doesn't set alpha (so it is 0), but the function is not meant to be used
248 // on bitmap with transparency. Should we set alpha to 0xff?
249 aDest = 0;
250 }
251
252 // kAdditiveBlenderMode
253 inline void blendAdditiveAlpha(uint8 aSrc, uint8 rSrc, uint8 gSrc, uint8 bSrc, uint8 &aDest, uint8 &rDest, uint8 &gDest, uint8 &bDest, uint32 alpha) const {
254 // Original blender function: _additive_alpha_copysrc_blender
255 rDest = rSrc;
256 gDest = gSrc;
257 bDest = bSrc;
258 uint32 a = (uint32)aSrc + (uint32)aDest;
259 if (a > 0xff)
260 aDest = 0xff;
261 else
262 aDest = static_cast<uint8>(a);
263 }
264
265 // kTintBlenderMode and kTintLightBlenderMode
266 void blendTintSprite(uint8 aSrc, uint8 rSrc, uint8 gSrc, uint8 bSrc, uint8 &aDest, uint8 &rDest, uint8 &gDest, uint8 &bDest, uint32 alpha, bool light) const;
267
268 friend class DrawInnerImpl_AVX2;
269 friend class DrawInnerImpl_SSE2;
270 friend class DrawInnerImpl_NEON;
271
272 constexpr static int SCALE_THRESHOLD_BITS = 8;
273 constexpr static int SCALE_THRESHOLD = 1 << SCALE_THRESHOLD_BITS;
274 struct DrawInnerArgs {
275 const bool useTint, horizFlip, vertFlip, skipTrans;
276 bool sameFormat, shouldDraw;
277 int xStart, yStart, srcAlpha, tintRed, tintGreen, tintBlue, scaleX, scaleY;
278 uint32 transColor, alphaMask;
279 PALETTE palette;
280
281 BlenderMode blenderMode;
282 Common::Rect dstRect, srcArea;
283
284 BITMAP &dstBitmap;
285 const ::Graphics::ManagedSurface &src;
286 ::Graphics::Surface destArea;
287
288 DrawInnerArgs(BITMAP *dstBitmap, const BITMAP *srcBitmap,
289 const Common::Rect &srcRect, const Common::Rect &dstRect,
290 bool skipTrans, int srcAlpha, bool horizFlip,
291 bool vertFlip, int tintRed, int tintGreen, int tintBlue,
292 bool doScale);
293 };
294
295 template<bool Scale>
296 void drawGeneric(DrawInnerArgs &args);
297#ifdef SCUMMVM_NEON
298 template<bool Scale>
299 void drawNEON(DrawInnerArgs &args);
300#endif
301#ifdef SCUMMVM_SSE2
302 template<bool Scale>
303 void drawSSE2(DrawInnerArgs &args);
304#endif
305#ifdef SCUMMVM_AVX2
306 template<bool Scale>
307 void drawAVX2(DrawInnerArgs &args);
308#endif
309 template<int DestBytesPerPixel, int SrcBytesPerPixel, bool Scale>
310 void drawInnerGeneric(DrawInnerArgs &args);
311
312 inline uint32 getColor(const byte *data, byte bpp) const {
313 switch (bpp) {
314 case 1:
315 return *data;
316 case 2:
317 return *(const uint16 *)data;
318 case 4:
319 return *(const uint32 *)data;
320 default:
321 error("Unsupported format in BITMAP::getColor");
322 }
323 }
324};
325
330public:
331 Surface(int width, int height, const Graphics::PixelFormat &pixelFormat) :
332 Graphics::ManagedSurface(width, height, pixelFormat), BITMAP(this) {
333 // Allegro uses 255, 0, 255 RGB as the transparent color
334 if (pixelFormat.bytesPerPixel == 2 || pixelFormat.bytesPerPixel == 4)
335 setTransparentColor(pixelFormat.RGBToColor(255, 0, 255));
336 }
337 Surface(Graphics::ManagedSurface &surf, const Common::Rect &bounds) :
338 Graphics::ManagedSurface(surf, bounds), BITMAP(this) {
339 // Allegro uses 255, 0, 255 RGB as the transparent color
340 if (surf.format.bytesPerPixel == 2 || surf.format.bytesPerPixel == 4)
341 setTransparentColor(surf.format.RGBToColor(255, 0, 255));
342 }
343 ~Surface() override {
344 }
345};
346
347BITMAP *create_bitmap(int width, int height);
348BITMAP *create_bitmap_ex(int color_depth, int width, int height);
349BITMAP *create_sub_bitmap(BITMAP *parent, int x, int y, int width, int height);
350BITMAP *create_video_bitmap(int width, int height);
351BITMAP *create_system_bitmap(int width, int height);
352void destroy_bitmap(BITMAP *bitmap);
353
354} // namespace AGS3
355
356#endif
Definition: surface.h:32
void draw(const BITMAP *srcBitmap, const Common::Rect &srcRect, int dstX, int dstY, bool horizFlip, bool vertFlip, bool skipTrans, int srcAlpha, int tintRed=-1, int tintGreen=-1, int tintBlue=-1)
void floodfill(int x, int y, int color)
void vLine(int x, int y, int y2, uint32 color)
Definition: surface.h:106
void stretchDraw(const BITMAP *srcBitmap, const Common::Rect &srcRect, const Common::Rect &destRect, bool skipTrans, int srcAlpha)
void circlefill(int x, int y, int radius, int color)
void hLine(int x, int y, int x2, uint32 color)
Definition: surface.h:99
Definition: surface.h:329
Definition: managed_surface.h:51
const void * getBasePtr(int x, int y) const
Definition: managed_surface.h:252
DisposeAfterUse::Flag disposeAfterUse() const
Definition: managed_surface.h:219
void clear(uint32 color=0)
void vLine(int x, int y, int y2, uint32 color)
Definition: managed_surface.h:946
PixelFormat & format
Definition: managed_surface.h:137
const Common::Point getOffsetFromOwner() const
Definition: managed_surface.h:323
void hLine(int x, int y, int x2, uint32 color)
Definition: managed_surface.h:938
void * getPixels()
Definition: managed_surface.h:271
void setTransparentColor(uint32 color)
Definition: managed_surface.h:1024
void NORETURN_PRE error(MSVC_PRINTF const char *s,...) GCC_PRINTF(1
Definition: color.h:49
Definition: rect.h:144
Definition: rect.h:536
Definition: pixelformat.h:138
uint32 RGBToColor(uint8 r, uint8 g, uint8 b) const
Definition: pixelformat.h:261
byte bytesPerPixel
Definition: pixelformat.h:139
Definition: surface.h:67