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 doscale, bool rgbmod, bool alphamod>
31 struct AlphaBlend {
32  static inline void normal(const byte *in, byte *out, const byte ca, const byte cr, const byte cg, const byte cb) {
33  uint32 ina = in[BlendBlit::kAIndex] * ca >> 8;
34 
35  if (ina != 0) {
36  if (rgbmod) {
37  const uint outb = (out[BlendBlit::kBIndex] * (255 - ina) >> 8);
38  const uint outg = (out[BlendBlit::kGIndex] * (255 - ina) >> 8);
39  const uint outr = (out[BlendBlit::kRIndex] * (255 - ina) >> 8);
40 
41  out[BlendBlit::kAIndex] = 255;
42  out[BlendBlit::kBIndex] = outb + (in[BlendBlit::kBIndex] * ina * cb >> 16);
43  out[BlendBlit::kGIndex] = outg + (in[BlendBlit::kGIndex] * ina * cg >> 16);
44  out[BlendBlit::kRIndex] = outr + (in[BlendBlit::kRIndex] * ina * cr >> 16);
45  } else {
46  out[BlendBlit::kAIndex] = 255;
47  out[BlendBlit::kBIndex] = (out[BlendBlit::kBIndex] * (255 - ina) + in[BlendBlit::kBIndex] * ina) >> 8;
48  out[BlendBlit::kGIndex] = (out[BlendBlit::kGIndex] * (255 - ina) + in[BlendBlit::kGIndex] * ina) >> 8;
49  out[BlendBlit::kRIndex] = (out[BlendBlit::kRIndex] * (255 - ina) + in[BlendBlit::kRIndex] * ina) >> 8;
50  }
51  }
52 
53  }
54 };
55 
56 template<bool doscale, bool rgbmod, bool alphamod>
57 struct MultiplyBlend {
58  static inline void normal(const byte *in, byte *out, const byte ca, const byte cr, const byte cg, const byte cb) {
59  uint32 ina = in[BlendBlit::kAIndex] * ca >> 8;
60 
61  if (ina != 0) {
62  out[BlendBlit::kBIndex] = out[BlendBlit::kBIndex] * ((in[BlendBlit::kBIndex] * cb * ina) >> 16) >> 8;
63  out[BlendBlit::kGIndex] = out[BlendBlit::kGIndex] * ((in[BlendBlit::kGIndex] * cg * ina) >> 16) >> 8;
64  out[BlendBlit::kRIndex] = out[BlendBlit::kRIndex] * ((in[BlendBlit::kRIndex] * cr * ina) >> 16) >> 8;
65  }
66  }
67 };
68 
69 template<bool doscale, bool rgbmod, bool alphamod>
70 struct OpaqueBlend {
71  static inline void normal(const byte *in, byte *out, const byte ca, const byte cr, const byte cg, const byte cb) {
72  *(uint32 *)out = *(const uint32 *)in | BlendBlit::kAModMask;
73  }
74 };
75 
76 template<bool doscale, bool rgbmod, bool alphamod>
77 struct BinaryBlend {
78  static inline void normal(const byte *in, byte *out, const byte ca, const byte cr, const byte cg, const byte cb) {
79  uint32 pix = *(const uint32 *)in;
80  int a = in[BlendBlit::kAIndex];
81 
82  if (a != 0) { // Full opacity (Any value not exactly 0 is Opaque here)
83  *(uint32 *)out = pix;
84  out[BlendBlit::kAIndex] = 0xFF;
85  }
86  }
87 };
88 
89 template<bool doscale, bool rgbmod, bool alphamod>
90 struct AdditiveBlend {
91  static inline void normal(const byte *in, byte *out, const byte ca, const byte cr, const byte cg, const byte cb) {
92  uint32 ina = in[BlendBlit::kAIndex] * ca >> 8;
93 
94  if (ina != 0) {
95  out[BlendBlit::kBIndex] = out[BlendBlit::kBIndex] + ((in[BlendBlit::kBIndex] * cb * ina) >> 16);
96  out[BlendBlit::kGIndex] = out[BlendBlit::kGIndex] + ((in[BlendBlit::kGIndex] * cg * ina) >> 16);
97  out[BlendBlit::kRIndex] = out[BlendBlit::kRIndex] + ((in[BlendBlit::kRIndex] * cr * ina) >> 16);
98  }
99  }
100 };
101 
102 template<bool doscale, bool rgbmod, bool alphamod>
104  static inline void normal(const byte *in, byte *out, const byte ca, const byte cr, const byte cg, const byte cb) {
105  out[BlendBlit::kAIndex] = 255;
106  out[BlendBlit::kBIndex] = MAX<int32>(out[BlendBlit::kBIndex] - ((in[BlendBlit::kBIndex] * cb * (out[BlendBlit::kBIndex]) * in[BlendBlit::kAIndex]) >> 24), 0);
107  out[BlendBlit::kGIndex] = MAX<int32>(out[BlendBlit::kGIndex] - ((in[BlendBlit::kGIndex] * cg * (out[BlendBlit::kGIndex]) * in[BlendBlit::kAIndex]) >> 24), 0);
108  out[BlendBlit::kRIndex] = MAX<int32>(out[BlendBlit::kRIndex] - ((in[BlendBlit::kRIndex] * cr * (out[BlendBlit::kRIndex]) * in[BlendBlit::kAIndex]) >> 24), 0);
109  }
110 };
111 
112 }; // End of class BlendBlitImpl_Base
113 
114 template<class T>
115 void BlendBlit::blitT(Args &args, const TSpriteBlendMode &blendMode, const AlphaType &alphaType) {
116  bool rgbmod = ((args.color & kRGBModMask) != kRGBModMask);
117  bool alphamod = ((args.color & kAModMask) != kAModMask);
118  if (args.scaleX == SCALE_THRESHOLD && args.scaleY == SCALE_THRESHOLD) {
119  if (args.color == 0xffffffff && blendMode == BLEND_NORMAL && alphaType == ALPHA_OPAQUE) {
120  T::template blitInnerLoop<T::template OpaqueBlend, false, false, false, false, true>(args);
121  } else if (args.color == 0xffffffff && blendMode == BLEND_NORMAL && alphaType == ALPHA_BINARY) {
122  T::template blitInnerLoop<T::template BinaryBlend, false, false, false, false, true>(args);
123  } else {
124  if (blendMode == BLEND_ADDITIVE) {
125  if (rgbmod) {
126  if (alphamod) {
127  T::template blitInnerLoop<T::template AdditiveBlend, false, true, true, false, true>(args);
128  } else {
129  T::template blitInnerLoop<T::template AdditiveBlend, false, true, false, false, true>(args);
130  }
131  } else {
132  if (alphamod) {
133  T::template blitInnerLoop<T::template AdditiveBlend, false, false, true, false, true>(args);
134  } else {
135  T::template blitInnerLoop<T::template AdditiveBlend, false, false, false, false, true>(args);
136  }
137  }
138  } else if (blendMode == BLEND_SUBTRACTIVE) {
139  if (rgbmod) {
140  T::template blitInnerLoop<T::template SubtractiveBlend, false, true, false, false, true>(args);
141  } else {
142  T::template blitInnerLoop<T::template SubtractiveBlend, false, false, false, false, true>(args);
143  }
144  } else if (blendMode == BLEND_MULTIPLY) {
145  if (rgbmod) {
146  if (alphamod) {
147  T::template blitInnerLoop<T::template MultiplyBlend, false, true, true, false, true>(args);
148  } else {
149  T::template blitInnerLoop<T::template MultiplyBlend, false, true, false, false, true>(args);
150  }
151  } else {
152  if (alphamod) {
153  T::template blitInnerLoop<T::template MultiplyBlend, false, false, true, false, true>(args);
154  } else {
155  T::template blitInnerLoop<T::template MultiplyBlend, false, false, false, false, true>(args);
156  }
157  }
158  } else {
159  assert(blendMode == BLEND_NORMAL);
160  if (rgbmod) {
161  if (alphamod) {
162  T::template blitInnerLoop<T::template AlphaBlend, false, true, true, false, true>(args);
163  } else {
164  T::template blitInnerLoop<T::template AlphaBlend, false, true, false, false, true>(args);
165  }
166  } else {
167  if (alphamod) {
168  T::template blitInnerLoop<T::template AlphaBlend, false, false, true, false, true>(args);
169  } else {
170  T::template blitInnerLoop<T::template AlphaBlend, false, false, false, false, true>(args);
171  }
172  }
173  }
174  }
175  } else {
176  if (args.color == 0xffffffff && blendMode == BLEND_NORMAL && alphaType == ALPHA_OPAQUE) {
177  T::template blitInnerLoop<T::template OpaqueBlend, true, false, false, false, true>(args);
178  } else if (args.color == 0xffffffff && blendMode == BLEND_NORMAL && alphaType == ALPHA_BINARY) {
179  T::template blitInnerLoop<T::template BinaryBlend, true, false, false, false, true>(args);
180  } else {
181  if (blendMode == BLEND_ADDITIVE) {
182  if (rgbmod) {
183  if (alphamod) {
184  T::template blitInnerLoop<T::template AdditiveBlend, true, true, true, false, true>(args);
185  } else {
186  T::template blitInnerLoop<T::template AdditiveBlend, true, true, false, false, true>(args);
187  }
188  } else {
189  if (alphamod) {
190  T::template blitInnerLoop<T::template AdditiveBlend, true, false, true, false, true>(args);
191  } else {
192  T::template blitInnerLoop<T::template AdditiveBlend, true, false, false, false, true>(args);
193  }
194  }
195  } else if (blendMode == BLEND_SUBTRACTIVE) {
196  if (rgbmod) {
197  T::template blitInnerLoop<T::template SubtractiveBlend, true, true, false, false, true>(args);
198  } else {
199  T::template blitInnerLoop<T::template SubtractiveBlend, true, false, false, false, true>(args);
200  }
201  } else if (blendMode == BLEND_MULTIPLY) {
202  if (rgbmod) {
203  if (alphamod) {
204  T::template blitInnerLoop<T::template MultiplyBlend, true, true, true, false, true>(args);
205  } else {
206  T::template blitInnerLoop<T::template MultiplyBlend, true, true, false, false, true>(args);
207  }
208  } else {
209  if (alphamod) {
210  T::template blitInnerLoop<T::template MultiplyBlend, true, false, true, false, true>(args);
211  } else {
212  T::template blitInnerLoop<T::template MultiplyBlend, true, false, false, false, true>(args);
213  }
214  }
215  } else {
216  assert(blendMode == BLEND_NORMAL);
217  if (rgbmod) {
218  if (alphamod) {
219  T::template blitInnerLoop<T::template AlphaBlend, true, true, true, false, true>(args);
220  } else {
221  T::template blitInnerLoop<T::template AlphaBlend, true, true, false, false, true>(args);
222  }
223  } else {
224  if (alphamod) {
225  T::template blitInnerLoop<T::template AlphaBlend, true, false, true, false, true>(args);
226  } else {
227  T::template blitInnerLoop<T::template AlphaBlend, true, false, false, false, true>(args);
228  }
229  }
230  }
231  }
232  }
233 }
234 
235 } // End of namespace Graphics
Definition: blit-alpha.h:31
Definition: formatinfo.h:28
Definition: blit.h:254
Definition: blit-alpha.h:26