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
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (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, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22 #include "common/system.h"
23 #include "graphics/macgui/macwindowmanager.h"
24
25 #include "director/director.h"
26
27 namespace Director {
28
29 #include "director/graphics-data.h"
30
31 /**
32 * The sprites colors are in reverse order with respect to the ids in director.
33 * The palette is in reverse order, this eases the code for loading files.
34 * All other color ids can be converted with: 255 - colorId.
35 **/
transformColor(uint32 color)36 uint32 DirectorEngine::transformColor(uint32 color) {
37 if (_pixelformat.bytesPerPixel == 1)
38 return 255 - color;
39
40 color = 255 - color;
41
42 return _wm->findBestColor(_currentPalette[color * 3], _currentPalette[color * 3 + 1], _currentPalette[color * 3 + 2]);
43 }
44
loadPatterns()45 void DirectorEngine::loadPatterns() {
46 for (int i = 0; i < ARRAYSIZE(director3Patterns); i++)
47 _director3Patterns.push_back(director3Patterns[i]);
48
49 for (int i = 0; i < ARRAYSIZE(director3QuickDrawPatterns); i++)
50 _director3QuickDrawPatterns.push_back(director3QuickDrawPatterns[i]);
51 }
52
getPatterns()53 Graphics::MacPatterns &DirectorEngine::getPatterns() {
54 // TOOD: implement switch and other version patterns. (use getVersion());
55 return _director3QuickDrawPatterns;
56 }
57
loadDefaultPalettes()58 void DirectorEngine::loadDefaultPalettes() {
59 _loadedPalettes[kClutSystemMac] = PaletteV4(kClutSystemMac, macPalette, 256);
60 _loadedPalettes[kClutRainbow] = PaletteV4(kClutRainbow, rainbowPalette, 256);
61 _loadedPalettes[kClutGrayscale] = PaletteV4(kClutGrayscale, grayscalePalette, 256);
62 _loadedPalettes[kClutPastels] = PaletteV4(kClutPastels, pastelsPalette, 256);
63 _loadedPalettes[kClutVivid] = PaletteV4(kClutVivid, vividPalette, 256);
64 _loadedPalettes[kClutNTSC] = PaletteV4(kClutNTSC, ntscPalette, 256);
65 _loadedPalettes[kClutMetallic] = PaletteV4(kClutMetallic, metallicPalette, 256);
66 _loadedPalettes[kClutSystemWin] = PaletteV4(kClutSystemWin, winPalette, 256);
67 }
68
getPalette(int id)69 PaletteV4 *DirectorEngine::getPalette(int id) {
70 if (!_loadedPalettes.contains(id)) {
71 warning("DirectorEngine::addPalette(): Palette %d not found", id);
72 return nullptr;
73 }
74
75 return &_loadedPalettes[id];
76 }
77
addPalette(int id,byte * palette,int length)78 void DirectorEngine::addPalette(int id, byte *palette, int length) {
79 if (id < 0) {
80 warning("DirectorEngine::addPalette(): Negative palette ids reserved for default palettes");
81 return;
82 } else if (_loadedPalettes.contains(id)) {
83 delete[] _loadedPalettes[id].palette;
84 }
85
86 _loadedPalettes[id] = PaletteV4(id, palette, length);
87 }
88
setPalette(int id)89 bool DirectorEngine::setPalette(int id) {
90 if (id == 0) {
91 // Palette id of 0 is unused
92 return false;
93 } else if (!_loadedPalettes.contains(id)) {
94 warning("setPalette(): no palette with matching id %d", id);
95 return false;
96 }
97
98 PaletteV4 pal = _loadedPalettes[id];
99 setPalette(pal.palette, pal.length);
100
101 return true;
102 }
103
setPalette(byte * palette,uint16 count)104 void DirectorEngine::setPalette(byte *palette, uint16 count) {
105 // Pass the palette to OSystem only for 8bpp mode
106 if (_pixelformat.bytesPerPixel == 1)
107 _system->getPaletteManager()->setPalette(palette, 0, count);
108
109 _currentPalette = palette;
110 _currentPaletteLength = count;
111
112 _wm->passPalette(palette, count);
113 }
114
clearPalettes()115 void DirectorEngine::clearPalettes() {
116 for (Common::HashMap<int, PaletteV4>::iterator it = _loadedPalettes.begin(); it != _loadedPalettes.end(); ++it) {
117 if (it->_value.id > 0)
118 delete[] it->_value.palette;
119 }
120 }
121
setCursor(DirectorCursor type)122 void DirectorEngine::setCursor(DirectorCursor type) {
123 switch (type) {
124 case kCursorMouseDown:
125 _wm->replaceCustomCursor(mouseDown, 16, 16, 0, 0, 3);
126 break;
127 case kCursorMouseUp:
128 _wm->replaceCustomCursor(mouseUp, 16, 16, 0, 0, 3);
129 break;
130 }
131 }
132
draw()133 void DirectorEngine::draw() {
134 _wm->renderZoomBox(true);
135 _wm->draw();
136 g_system->updateScreen();
137 }
138
139 template <typename T>
inkDrawPixel(int x,int y,int src,void * data)140 void inkDrawPixel(int x, int y, int src, void *data) {
141 DirectorPlotData *p = (DirectorPlotData *)data;
142
143 if (!p->destRect.contains(x, y))
144 return;
145
146 T dst;
147 uint32 tmpDst;
148
149 dst = (T)p->dst->getBasePtr(x, y);
150
151 if (p->ms) {
152 // Get the pixel that macDrawPixel will give us, but store it to apply the
153 // ink later
154 tmpDst = *dst;
155 (p->_wm->getDrawPixel())(x, y, src, p->ms->pd);
156 src = *dst;
157
158 *dst = tmpDst;
159 } else if (p->alpha) {
160 // Sprite blend does not respect colourization; defaults to matte ink
161 byte rSrc, gSrc, bSrc;
162 byte rDst, gDst, bDst;
163
164 g_director->_wm->decomposeColor(src, rSrc, gSrc, bSrc);
165 g_director->_wm->decomposeColor(*dst, rDst, gDst, bDst);
166
167 double alpha = (double)p->alpha / 100.0;
168 rDst = static_cast<byte>((rSrc * alpha) + (rDst * (1.0 - alpha)));
169 gDst = static_cast<byte>((gSrc * alpha) + (gDst * (1.0 - alpha)));
170 bDst = static_cast<byte>((bSrc * alpha) + (bDst * (1.0 - alpha)));
171
172 *dst = p->_wm->findBestColor(rDst, gDst, bDst);
173 return;
174 }
175
176 switch (p->ink) {
177 case kInkTypeBackgndTrans:
178 if ((uint32)src == p->backColor)
179 break;
180 // fall through
181 case kInkTypeMatte:
182 case kInkTypeMask:
183 // Only unmasked pixels make it here, so copy them straight
184 case kInkTypeCopy: {
185 if (p->applyColor) {
186 // TODO: Improve the efficiency of this composition
187 byte rSrc, gSrc, bSrc;
188 byte rDst, gDst, bDst;
189 byte rFor, gFor, bFor;
190 byte rBak, gBak, bBak;
191
192 g_director->_wm->decomposeColor(src, rSrc, gSrc, bSrc);
193 g_director->_wm->decomposeColor(*dst, rDst, gDst, bDst);
194 g_director->_wm->decomposeColor(p->foreColor, rFor, gFor, bFor);
195 g_director->_wm->decomposeColor(p->backColor, rBak, gBak, bBak);
196
197 *dst = p->_wm->findBestColor((rSrc | rFor) & (~rSrc | rBak),
198 (gSrc | gFor) & (~gSrc | gBak),
199 (bSrc | bFor) & (~bSrc | bBak));
200 } else {
201 *dst = src;
202 }
203 break;
204 }
205 case kInkTypeNotCopy:
206 if (p->applyColor) {
207 // TODO: Improve the efficiency of this composition
208 byte rSrc, gSrc, bSrc;
209 byte rDst, gDst, bDst;
210 byte rFor, gFor, bFor;
211 byte rBak, gBak, bBak;
212
213 g_director->_wm->decomposeColor(src, rSrc, gSrc, bSrc);
214 g_director->_wm->decomposeColor(*dst, rDst, gDst, bDst);
215 g_director->_wm->decomposeColor(p->foreColor, rFor, gFor, bFor);
216 g_director->_wm->decomposeColor(p->backColor, rBak, gBak, bBak);
217
218 *dst = p->_wm->findBestColor((~rSrc | rFor) & (rSrc | rBak),
219 (~gSrc | gFor) & (gSrc | gBak),
220 (~bSrc | bFor) & (bSrc | bBak));
221 } else {
222 *dst = src;
223 }
224 break;
225 case kInkTypeTransparent:
226 *dst = p->applyColor ? (~src & p->foreColor) | (*dst & src) : (*dst & src);
227 break;
228 case kInkTypeNotTrans:
229 *dst = p->applyColor ? (src & p->foreColor) | (*dst & ~src) : (*dst & ~src);
230 break;
231 case kInkTypeReverse:
232 *dst ^= ~(src);
233 break;
234 case kInkTypeNotReverse:
235 *dst ^= src;
236 break;
237 case kInkTypeGhost:
238 *dst = p->applyColor ? (src | p->backColor) & (*dst | ~src) : (*dst | ~src);
239 break;
240 case kInkTypeNotGhost:
241 *dst = p->applyColor ? (~src | p->backColor) & (*dst | src) : *dst | src;
242 break;
243 // Arithmetic ink types
244 default: {
245 byte rSrc, gSrc, bSrc;
246 byte rDst, gDst, bDst;
247
248 g_director->_wm->decomposeColor(src, rSrc, gSrc, bSrc);
249 g_director->_wm->decomposeColor(*dst, rDst, gDst, bDst);
250
251 switch (p->ink) {
252 case kInkTypeBlend:
253 *dst = p->_wm->findBestColor((rSrc + rDst) / 2, (gSrc + gDst) / 2, (bSrc + bDst) / 2);
254 break;
255 case kInkTypeAddPin:
256 *dst = p->_wm->findBestColor(MIN((rSrc + rDst), 0xff), MIN((gSrc + gDst), 0xff), MIN((bSrc + bDst), 0xff));
257 break;
258 case kInkTypeAdd:
259 // in basilisk, D3.1 is exactly using this method, adding color directly without preventing the overflow.
260 // but i think min(src + dst, 255) will give us a better visual effect
261 *dst = p->_wm->findBestColor(rSrc + rDst, gSrc + gDst, bSrc + bDst);
262 break;
263 case kInkTypeSubPin:
264 *dst = p->_wm->findBestColor(MAX(rSrc - rDst, 0), MAX(gSrc - gDst, 0), MAX(bSrc - bDst, 0));
265 break;
266 case kInkTypeLight:
267 *dst = p->_wm->findBestColor(MAX(rSrc, rDst), MAX(gSrc, gDst), MAX(bSrc, bDst));
268 break;
269 case kInkTypeSub:
270 *dst = p->_wm->findBestColor(abs(rSrc - rDst) % 0xff + 1, abs(gSrc - gDst) % 0xff + 1, abs(bSrc - bDst) % 0xff + 1);
271 break;
272 case kInkTypeDark:
273 *dst = p->_wm->findBestColor(MIN(rSrc, rDst), MIN(gSrc, gDst), MIN(bSrc, bDst));
274 break;
275 default:
276 break;
277 }
278 }
279 }
280 }
281
getInkDrawPixel()282 Graphics::MacDrawPixPtr DirectorEngine::getInkDrawPixel() {
283 if (_pixelformat.bytesPerPixel == 1)
284 return &inkDrawPixel<byte *>;
285 else
286 return &inkDrawPixel<uint32 *>;
287 }
288
setApplyColor()289 void DirectorPlotData::setApplyColor() {
290 applyColor = false;
291
292 if (foreColor != colorBlack) {
293 if (ink != kInkTypeGhost && ink != kInkTypeNotGhost)
294 applyColor = true;
295 }
296
297 if (backColor != colorWhite) {
298 if (ink != kInkTypeTransparent && ink != kInkTypeNotTrans && ink != kInkTypeBackgndTrans)
299 applyColor = true;
300 }
301 }
302
303 } // End of namespace Director
304