ScummVM API documentation
blit-alpha.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 #include "graphics/blit.h"
23 
24 namespace Graphics {
25 
27  friend class BlendBlit;
28 protected:
29 
30 template<bool rgbmod, bool alphamod>
31 struct BaseBlend {
32 public:
33  constexpr BaseBlend(const uint32 color) :
34  ca(alphamod ? ((color >> BlendBlit::kAModShift) & 0xFF) : 255),
35  cr(rgbmod ? ((color >> BlendBlit::kRModShift) & 0xFF) : 255),
36  cg(rgbmod ? ((color >> BlendBlit::kGModShift) & 0xFF) : 255),
37  cb(rgbmod ? ((color >> BlendBlit::kBModShift) & 0xFF) : 255) {}
38 
39 protected:
40  const byte ca, cr, cg, cb;
41 };
42 
43 template<bool rgbmod, bool alphamod>
44 struct AlphaBlend : public BaseBlend<rgbmod, alphamod> {
45 public:
46  constexpr AlphaBlend(const uint32 color) : BaseBlend<rgbmod, alphamod>(color) {}
47 
48  inline void normal(const byte *in, byte *out) const {
49  uint32 ina;
50 
51  if (alphamod) {
52  ina = in[BlendBlit::kAIndex] * this->ca >> 8;
53  } else {
54  ina = in[BlendBlit::kAIndex];
55  }
56 
57  if (ina == 255) {
58  if (rgbmod) {
59  out[BlendBlit::kAIndex] = 255;
60  out[BlendBlit::kBIndex] = (in[BlendBlit::kBIndex] * this->cb >> 8);
61  out[BlendBlit::kGIndex] = (in[BlendBlit::kGIndex] * this->cg >> 8);
62  out[BlendBlit::kRIndex] = (in[BlendBlit::kRIndex] * this->cr >> 8);
63  } else {
64  out[BlendBlit::kAIndex] = 255;
65  out[BlendBlit::kBIndex] = in[BlendBlit::kBIndex];
66  out[BlendBlit::kGIndex] = in[BlendBlit::kGIndex];
67  out[BlendBlit::kRIndex] = in[BlendBlit::kRIndex];
68  }
69  } else if (ina != 0) {
70  if (rgbmod) {
71  const uint outb = (out[BlendBlit::kBIndex] * (255 - ina) >> 8);
72  const uint outg = (out[BlendBlit::kGIndex] * (255 - ina) >> 8);
73  const uint outr = (out[BlendBlit::kRIndex] * (255 - ina) >> 8);
74 
75  out[BlendBlit::kAIndex] = 255;
76  out[BlendBlit::kBIndex] = outb + (in[BlendBlit::kBIndex] * ina * this->cb >> 16);
77  out[BlendBlit::kGIndex] = outg + (in[BlendBlit::kGIndex] * ina * this->cg >> 16);
78  out[BlendBlit::kRIndex] = outr + (in[BlendBlit::kRIndex] * ina * this->cr >> 16);
79  } else {
80  out[BlendBlit::kAIndex] = 255;
81  out[BlendBlit::kBIndex] = (out[BlendBlit::kBIndex] * (255 - ina) + in[BlendBlit::kBIndex] * ina) >> 8;
82  out[BlendBlit::kGIndex] = (out[BlendBlit::kGIndex] * (255 - ina) + in[BlendBlit::kGIndex] * ina) >> 8;
83  out[BlendBlit::kRIndex] = (out[BlendBlit::kRIndex] * (255 - ina) + in[BlendBlit::kRIndex] * ina) >> 8;
84  }
85  }
86 
87  }
88 };
89 
90 template<bool rgbmod, bool alphamod>
91 struct MultiplyBlend : public BaseBlend<rgbmod, alphamod> {
92 public:
93  constexpr MultiplyBlend(const uint32 color) : BaseBlend<rgbmod, alphamod>(color) {}
94 
95  inline void normal(const byte *in, byte *out) const {
96  uint32 ina;
97 
98  if (alphamod) {
99  ina = in[BlendBlit::kAIndex] * this->ca >> 8;
100  } else {
101  ina = in[BlendBlit::kAIndex];
102  }
103 
104  if (ina == 255) {
105  if (rgbmod) {
106  out[BlendBlit::kBIndex] = out[BlendBlit::kBIndex] * ((in[BlendBlit::kBIndex] * this->cb) >> 8) >> 8;
107  out[BlendBlit::kGIndex] = out[BlendBlit::kGIndex] * ((in[BlendBlit::kGIndex] * this->cg) >> 8) >> 8;
108  out[BlendBlit::kRIndex] = out[BlendBlit::kRIndex] * ((in[BlendBlit::kRIndex] * this->cr) >> 8) >> 8;
109  } else {
110  out[BlendBlit::kBIndex] = out[BlendBlit::kBIndex] * in[BlendBlit::kBIndex] >> 8;
111  out[BlendBlit::kGIndex] = out[BlendBlit::kGIndex] * in[BlendBlit::kGIndex] >> 8;
112  out[BlendBlit::kRIndex] = out[BlendBlit::kRIndex] * in[BlendBlit::kRIndex] >> 8;
113  }
114  } else if (ina != 0) {
115  if (rgbmod) {
116  out[BlendBlit::kBIndex] = out[BlendBlit::kBIndex] * ((in[BlendBlit::kBIndex] * this->cb * ina) >> 16) >> 8;
117  out[BlendBlit::kGIndex] = out[BlendBlit::kGIndex] * ((in[BlendBlit::kGIndex] * this->cg * ina) >> 16) >> 8;
118  out[BlendBlit::kRIndex] = out[BlendBlit::kRIndex] * ((in[BlendBlit::kRIndex] * this->cr * ina) >> 16) >> 8;
119  } else {
120  out[BlendBlit::kBIndex] = out[BlendBlit::kBIndex] * ((in[BlendBlit::kBIndex] * ina) >> 8) >> 8;
121  out[BlendBlit::kGIndex] = out[BlendBlit::kGIndex] * ((in[BlendBlit::kGIndex] * ina) >> 8) >> 8;
122  out[BlendBlit::kRIndex] = out[BlendBlit::kRIndex] * ((in[BlendBlit::kRIndex] * ina) >> 8) >> 8;
123  }
124  }
125  }
126 };
127 
128 template<bool rgbmod, bool alphamod>
129 struct OpaqueBlend : public BaseBlend<rgbmod, alphamod> {
130 public:
131  constexpr OpaqueBlend(const uint32 color) : BaseBlend<rgbmod, alphamod>(color) {}
132 
133  inline void normal(const byte *in, byte *out) const {
134  *(uint32 *)out = *(const uint32 *)in | BlendBlit::kAModMask;
135  }
136 };
137 
138 template<bool rgbmod, bool alphamod>
139 struct BinaryBlend : public BaseBlend<rgbmod, alphamod> {
140 public:
141  constexpr BinaryBlend(const uint32 color) : BaseBlend<rgbmod, alphamod>(color) {}
142 
143  inline void normal(const byte *in, byte *out) const {
144  uint32 pix = *(const uint32 *)in;
145  uint32 a = pix & BlendBlit::kAModMask;
146 
147  if (a != 0) { // Full opacity (Any value not exactly 0 is Opaque here)
148  *(uint32 *)out = pix | BlendBlit::kAModMask;
149  }
150  }
151 };
152 
153 template<bool rgbmod, bool alphamod>
154 struct AdditiveBlend : public BaseBlend<rgbmod, alphamod> {
155 public:
156  constexpr AdditiveBlend(const uint32 color) : BaseBlend<rgbmod, alphamod>(color) {}
157 
158  inline void normal(const byte *in, byte *out) const {
159  uint32 ina;
160 
161  if (alphamod) {
162  ina = in[BlendBlit::kAIndex] * this->ca >> 8;
163  } else {
164  ina = in[BlendBlit::kAIndex];
165  }
166 
167  if (ina == 255) {
168  if (rgbmod) {
169  out[BlendBlit::kBIndex] = out[BlendBlit::kBIndex] + ((in[BlendBlit::kBIndex] * this->cb) >> 8);
170  out[BlendBlit::kGIndex] = out[BlendBlit::kGIndex] + ((in[BlendBlit::kGIndex] * this->cg) >> 8);
171  out[BlendBlit::kRIndex] = out[BlendBlit::kRIndex] + ((in[BlendBlit::kRIndex] * this->cr) >> 8);
172  } else {
173  out[BlendBlit::kBIndex] = out[BlendBlit::kBIndex] + in[BlendBlit::kBIndex];
174  out[BlendBlit::kGIndex] = out[BlendBlit::kGIndex] + in[BlendBlit::kGIndex];
175  out[BlendBlit::kRIndex] = out[BlendBlit::kRIndex] + in[BlendBlit::kRIndex];
176  }
177  } else if (ina != 0) {
178  if (rgbmod) {
179  out[BlendBlit::kBIndex] = out[BlendBlit::kBIndex] + ((in[BlendBlit::kBIndex] * this->cb * ina) >> 16);
180  out[BlendBlit::kGIndex] = out[BlendBlit::kGIndex] + ((in[BlendBlit::kGIndex] * this->cg * ina) >> 16);
181  out[BlendBlit::kRIndex] = out[BlendBlit::kRIndex] + ((in[BlendBlit::kRIndex] * this->cr * ina) >> 16);
182  } else {
183  out[BlendBlit::kBIndex] = out[BlendBlit::kBIndex] + ((in[BlendBlit::kBIndex] * ina) >> 8);
184  out[BlendBlit::kGIndex] = out[BlendBlit::kGIndex] + ((in[BlendBlit::kGIndex] * ina) >> 8);
185  out[BlendBlit::kRIndex] = out[BlendBlit::kRIndex] + ((in[BlendBlit::kRIndex] * ina) >> 8);
186  }
187  }
188  }
189 };
190 
191 template<bool rgbmod, bool alphamod>
192 struct SubtractiveBlend : public BaseBlend<rgbmod, alphamod> {
193 public:
194  constexpr SubtractiveBlend(const uint32 color) : BaseBlend<rgbmod, alphamod>(color) {}
195 
196  inline void normal(const byte *in, byte *out) const {
197  uint32 ina = in[BlendBlit::kAIndex];
198  out[BlendBlit::kAIndex] = 255;
199 
200  if (ina == 255) {
201  if (rgbmod) {
202  out[BlendBlit::kBIndex] = MAX<int32>(out[BlendBlit::kBIndex] - ((in[BlendBlit::kBIndex] * this->cb * (out[BlendBlit::kBIndex])) >> 16), 0);
203  out[BlendBlit::kGIndex] = MAX<int32>(out[BlendBlit::kGIndex] - ((in[BlendBlit::kGIndex] * this->cg * (out[BlendBlit::kGIndex])) >> 16), 0);
204  out[BlendBlit::kRIndex] = MAX<int32>(out[BlendBlit::kRIndex] - ((in[BlendBlit::kRIndex] * this->cr * (out[BlendBlit::kRIndex])) >> 16), 0);
205  } else {
206  out[BlendBlit::kBIndex] = MAX<int32>(out[BlendBlit::kBIndex] - ((in[BlendBlit::kBIndex] * (out[BlendBlit::kBIndex])) >> 8), 0);
207  out[BlendBlit::kGIndex] = MAX<int32>(out[BlendBlit::kGIndex] - ((in[BlendBlit::kGIndex] * (out[BlendBlit::kGIndex])) >> 8), 0);
208  out[BlendBlit::kRIndex] = MAX<int32>(out[BlendBlit::kRIndex] - ((in[BlendBlit::kRIndex] * (out[BlendBlit::kRIndex])) >> 8), 0);
209  }
210  } else if (ina != 0) {
211  if (rgbmod) {
212  out[BlendBlit::kBIndex] = MAX<int32>(out[BlendBlit::kBIndex] - ((in[BlendBlit::kBIndex] * this->cb * (out[BlendBlit::kBIndex]) * ina) >> 24), 0);
213  out[BlendBlit::kGIndex] = MAX<int32>(out[BlendBlit::kGIndex] - ((in[BlendBlit::kGIndex] * this->cg * (out[BlendBlit::kGIndex]) * ina) >> 24), 0);
214  out[BlendBlit::kRIndex] = MAX<int32>(out[BlendBlit::kRIndex] - ((in[BlendBlit::kRIndex] * this->cr * (out[BlendBlit::kRIndex]) * ina) >> 24), 0);
215  } else {
216  out[BlendBlit::kBIndex] = MAX<int32>(out[BlendBlit::kBIndex] - ((in[BlendBlit::kBIndex] * (out[BlendBlit::kBIndex]) * ina) >> 16), 0);
217  out[BlendBlit::kGIndex] = MAX<int32>(out[BlendBlit::kGIndex] - ((in[BlendBlit::kGIndex] * (out[BlendBlit::kGIndex]) * ina) >> 16), 0);
218  out[BlendBlit::kRIndex] = MAX<int32>(out[BlendBlit::kRIndex] - ((in[BlendBlit::kRIndex] * (out[BlendBlit::kRIndex]) * ina) >> 16), 0);
219  }
220  }
221  }
222 };
223 
224 }; // End of class BlendBlitImpl_Base
225 
226 template<class T>
227 void BlendBlit::blitT(Args &args, const TSpriteBlendMode &blendMode, const AlphaType &alphaType) {
228  bool rgbmod = ((args.color & kRGBModMask) != kRGBModMask);
229  bool alphamod = ((args.color & kAModMask) != kAModMask);
230  if (args.scaleX == SCALE_THRESHOLD && args.scaleY == SCALE_THRESHOLD) {
231  if (args.color == 0xffffffff && blendMode == BLEND_NORMAL && alphaType == ALPHA_OPAQUE) {
232  T::template blitInnerLoop<T::template OpaqueBlend, false, false, false>(args);
233  } else if (args.color == 0xffffffff && blendMode == BLEND_NORMAL && alphaType == ALPHA_BINARY) {
234  T::template blitInnerLoop<T::template BinaryBlend, false, false, false>(args);
235  } else {
236  if (blendMode == BLEND_ADDITIVE) {
237  if (rgbmod) {
238  if (alphamod) {
239  T::template blitInnerLoop<T::template AdditiveBlend, false, true, true>(args);
240  } else {
241  T::template blitInnerLoop<T::template AdditiveBlend, false, true, false>(args);
242  }
243  } else {
244  if (alphamod) {
245  T::template blitInnerLoop<T::template AdditiveBlend, false, false, true>(args);
246  } else {
247  T::template blitInnerLoop<T::template AdditiveBlend, false, false, false>(args);
248  }
249  }
250  } else if (blendMode == BLEND_SUBTRACTIVE) {
251  if (rgbmod) {
252  T::template blitInnerLoop<T::template SubtractiveBlend, false, true, false>(args);
253  } else {
254  T::template blitInnerLoop<T::template SubtractiveBlend, false, false, false>(args);
255  }
256  } else if (blendMode == BLEND_MULTIPLY) {
257  if (rgbmod) {
258  if (alphamod) {
259  T::template blitInnerLoop<T::template MultiplyBlend, false, true, true>(args);
260  } else {
261  T::template blitInnerLoop<T::template MultiplyBlend, false, true, false>(args);
262  }
263  } else {
264  if (alphamod) {
265  T::template blitInnerLoop<T::template MultiplyBlend, false, false, true>(args);
266  } else {
267  T::template blitInnerLoop<T::template MultiplyBlend, false, false, false>(args);
268  }
269  }
270  } else {
271  assert(blendMode == BLEND_NORMAL);
272  if (rgbmod) {
273  if (alphamod) {
274  T::template blitInnerLoop<T::template AlphaBlend, false, true, true>(args);
275  } else {
276  T::template blitInnerLoop<T::template AlphaBlend, false, true, false>(args);
277  }
278  } else {
279  if (alphamod) {
280  T::template blitInnerLoop<T::template AlphaBlend, false, false, true>(args);
281  } else {
282  T::template blitInnerLoop<T::template AlphaBlend, false, false, false>(args);
283  }
284  }
285  }
286  }
287  } else {
288  if (args.color == 0xffffffff && blendMode == BLEND_NORMAL && alphaType == ALPHA_OPAQUE) {
289  T::template blitInnerLoop<T::template OpaqueBlend, true, false, false>(args);
290  } else if (args.color == 0xffffffff && blendMode == BLEND_NORMAL && alphaType == ALPHA_BINARY) {
291  T::template blitInnerLoop<T::template BinaryBlend, true, false, false>(args);
292  } else {
293  if (blendMode == BLEND_ADDITIVE) {
294  if (rgbmod) {
295  if (alphamod) {
296  T::template blitInnerLoop<T::template AdditiveBlend, true, true, true>(args);
297  } else {
298  T::template blitInnerLoop<T::template AdditiveBlend, true, true, false>(args);
299  }
300  } else {
301  if (alphamod) {
302  T::template blitInnerLoop<T::template AdditiveBlend, true, false, true>(args);
303  } else {
304  T::template blitInnerLoop<T::template AdditiveBlend, true, false, false>(args);
305  }
306  }
307  } else if (blendMode == BLEND_SUBTRACTIVE) {
308  if (rgbmod) {
309  T::template blitInnerLoop<T::template SubtractiveBlend, true, true, false>(args);
310  } else {
311  T::template blitInnerLoop<T::template SubtractiveBlend, true, false, false>(args);
312  }
313  } else if (blendMode == BLEND_MULTIPLY) {
314  if (rgbmod) {
315  if (alphamod) {
316  T::template blitInnerLoop<T::template MultiplyBlend, true, true, true>(args);
317  } else {
318  T::template blitInnerLoop<T::template MultiplyBlend, true, true, false>(args);
319  }
320  } else {
321  if (alphamod) {
322  T::template blitInnerLoop<T::template MultiplyBlend, true, false, true>(args);
323  } else {
324  T::template blitInnerLoop<T::template MultiplyBlend, true, false, false>(args);
325  }
326  }
327  } else {
328  assert(blendMode == BLEND_NORMAL);
329  if (rgbmod) {
330  if (alphamod) {
331  T::template blitInnerLoop<T::template AlphaBlend, true, true, true>(args);
332  } else {
333  T::template blitInnerLoop<T::template AlphaBlend, true, true, false>(args);
334  }
335  } else {
336  if (alphamod) {
337  T::template blitInnerLoop<T::template AlphaBlend, true, false, true>(args);
338  } else {
339  T::template blitInnerLoop<T::template AlphaBlend, true, false, false>(args);
340  }
341  }
342  }
343  }
344  }
345 }
346 
347 } // End of namespace Graphics
Definition: blit-alpha.h:44
Definition: blit-alpha.h:139
Definition: formatinfo.h:28
Definition: blit.h:254
Definition: blit-alpha.h:31
Definition: blit-alpha.h:129
Definition: blit-alpha.h:26