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
23 #include "common/debug.h"
24 #include "common/file.h"
25
26 #include "sludge/graphics.h"
27 #include "sludge/newfatal.h"
28 #include "sludge/variable.h"
29
30 namespace Sludge {
31
32 #if 0
33 // Raised
34 static int s_matrixEffectDivide = 2;
35 static int s_matrixEffectWidth = 3;
36 static int s_matrixEffectHeight = 3;
37 static int s_matrixEffectData[9] = {0, 0, 0, 0, -1, 0, 0, 0, 2};
38 static int s_matrixEffectBase = 0;
39 #elif 0
40 // Stay put
41 static int s_matrixEffectDivide = 1;
42 static int s_matrixEffectWidth = 3;
43 static int s_matrixEffectHeight = 3;
44 static int s_matrixEffectData[9] = {0, 0, 0, 0, 1, 0, 0, 0, 0};
45 static int s_matrixEffectBase = 0;
46 #elif 0
47 // Brighten
48 static int s_matrixEffectDivide = 9;
49 static int s_matrixEffectWidth = 1;
50 static int s_matrixEffectHeight = 1;
51 static int s_matrixEffectData[9] = {10};
52 static int s_matrixEffectBase = 15;
53 #elif 0
54 // Raised up/left
55 static int s_matrixEffectDivide = 4;
56 static int s_matrixEffectWidth = 3;
57 static int s_matrixEffectHeight = 3;
58 static int s_matrixEffectData[9] = {-2, -1, 0, -1, 1, 1, 0, 1, 2};
59 static int s_matrixEffectBase = 16;
60 #elif 0
61 // Standard emboss
62 static int s_matrixEffectDivide = 2;
63 static int s_matrixEffectWidth = 3;
64 static int s_matrixEffectHeight = 3;
65 static int s_matrixEffectData[9] = {-1, 0, 0, 0, 0, 0, 0, 0, 1};
66 static int s_matrixEffectBase = 128;
67 #elif 0
68 // Horizontal blur
69 static int s_matrixEffectDivide = 11;
70 static int s_matrixEffectWidth = 5;
71 static int s_matrixEffectHeight = 1;
72 static int s_matrixEffectData[9] = {1, 3, 3, 3, 1};
73 static int s_matrixEffectBase = 0;
74 #elif 0
75 // Double vision
76 static int s_matrixEffectDivide = 6;
77 static int s_matrixEffectWidth = 13;
78 static int s_matrixEffectHeight = 2;
79 static int s_matrixEffectData[26] = {2, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3};
80 static int s_matrixEffectBase = 0;
81 #elif 0
82 // Negative
83 static int s_matrixEffectDivide = 1;
84 static int s_matrixEffectWidth = 1;
85 static int s_matrixEffectHeight = 1;
86 static int s_matrixEffectData[9] = {-1};
87 static int s_matrixEffectBase = 255;
88 #elif 0
89 // Fog
90 static int s_matrixEffectDivide = 4;
91 static int s_matrixEffectWidth = 1;
92 static int s_matrixEffectHeight = 1;
93 static int s_matrixEffectData[9] = {3};
94 static int s_matrixEffectBase = 45;
95 #elif 0
96 // Blur
97 static int s_matrixEffectDivide = 14;
98 static int s_matrixEffectWidth = 3;
99 static int s_matrixEffectHeight = 3;
100 static int s_matrixEffectData[9] = {1, 2, 1, 2, 2, 2, 1, 2, 1};
101 static int s_matrixEffectBase = 0;
102 #else
103 static int s_matrixEffectDivide = 0;
104 static int s_matrixEffectWidth = 0;
105 static int s_matrixEffectHeight = 0;
106 static int *s_matrixEffectData = NULL;
107 static int s_matrixEffectBase = 0;
108 #endif
109
blur_saveSettings(Common::WriteStream * stream)110 void GraphicsManager::blur_saveSettings(Common::WriteStream *stream) {
111 if (s_matrixEffectData) {
112 stream->writeUint32LE(s_matrixEffectDivide);
113 stream->writeUint32LE(s_matrixEffectWidth);
114 stream->writeUint32LE(s_matrixEffectHeight);
115 stream->writeUint32LE(s_matrixEffectBase);
116 stream->write(s_matrixEffectData, sizeof(int) * s_matrixEffectWidth * s_matrixEffectHeight);
117 } else {
118 stream->writeUint32LE(0);
119 stream->writeUint32LE(0);
120 stream->writeUint32LE(0);
121 stream->writeUint32LE(0);
122 }
123 }
124
blur_allocateMemoryForEffect()125 static int *blur_allocateMemoryForEffect() {
126 free(s_matrixEffectData);
127 s_matrixEffectData = NULL;
128
129 if (s_matrixEffectWidth && s_matrixEffectHeight) {
130 s_matrixEffectData = (int *)malloc(sizeof(int) * s_matrixEffectHeight * s_matrixEffectWidth);
131 checkNew(s_matrixEffectData);
132 }
133 return s_matrixEffectData;
134 }
135
blur_loadSettings(Common::SeekableReadStream * stream)136 void GraphicsManager::blur_loadSettings(Common::SeekableReadStream *stream) {
137 s_matrixEffectDivide = stream->readUint32LE();
138 s_matrixEffectWidth = stream->readUint32LE();
139 s_matrixEffectHeight = stream->readUint32LE();
140 s_matrixEffectBase = stream->readUint32LE();
141
142 if (blur_allocateMemoryForEffect()) {
143 uint bytes_read = stream->read(s_matrixEffectData, sizeof(int) * s_matrixEffectWidth * s_matrixEffectHeight);
144 if (bytes_read != sizeof(int) * s_matrixEffectWidth * s_matrixEffectHeight && stream->err()) {
145 debug("Reading error in blur_loadSettings.");
146 }
147 } else {
148 stream->seek(sizeof(int) * s_matrixEffectWidth * s_matrixEffectHeight, SEEK_CUR);
149 }
150 }
151
blur_createSettings(int numParams,VariableStack * & stack)152 bool GraphicsManager::blur_createSettings(int numParams, VariableStack *&stack) {
153 bool createNullThing = true;
154 Common::String error = "";
155
156 if (numParams >= 3) {
157 // PARAMETERS: base, divide, stack (, stack (, stack...))
158
159 int height = numParams - 2;
160 int width = 0;
161
162 VariableStack *justToCheckSizes = stack;
163 for (int a = 0; a < height; a++) {
164 if (justToCheckSizes->thisVar.varType != SVT_STACK) {
165 error = "Third and subsequent parameters in setBackgroundEffect should be arrays";
166 break;
167 } else {
168 int w = justToCheckSizes->thisVar.varData.theStack->getStackSize();
169 if (a) {
170 if (w != width) {
171 error = "Arrays in setBackgroundEffect must be the same size";
172 break;
173 }
174 if (w < width) {
175 width = w;
176 }
177 } else {
178 width = w;
179 }
180 }
181 }
182
183 if (width == 0 && error.empty()) {
184 error = "Empty arrays found in setBackgroundEffect parameters";
185 }
186
187 if (error.empty()) {
188 s_matrixEffectWidth = width;
189 s_matrixEffectHeight = height;
190
191 if (blur_allocateMemoryForEffect()) {
192 for (int y = height - 1; y >= 0; y--) {
193 VariableStack *eachNumber = stack->thisVar.varData.theStack->first;
194 if (error.empty()) {
195 for (int x = 0; x < width; x++) {
196 int arraySlot = x + (y * width);
197 // s_matrixEffectData[arraySlot] = (rand() % 4);
198 if (!eachNumber->thisVar.getValueType(s_matrixEffectData[arraySlot], SVT_INT)) {
199 error = "";
200 break;
201 }
202 eachNumber = eachNumber->next;
203 }
204 trimStack(stack);
205 }
206 }
207 if (error.empty() && !stack->thisVar.getValueType(s_matrixEffectDivide, SVT_INT))
208 error = "";
209 trimStack(stack);
210 if (error.empty() && !stack->thisVar.getValueType(s_matrixEffectBase, SVT_INT))
211 error = "";
212 trimStack(stack);
213 if (error.empty()) {
214 if (s_matrixEffectDivide) {
215 createNullThing = false;
216 } else {
217 error = "Second parameter of setBackgroundEffect (the 'divide' value) should not be 0!";
218 }
219 }
220 } else {
221 error = "Couldn't allocate memory for effect";
222 }
223 }
224 } else {
225 if (numParams) {
226 error = "setBackgroundEffect should either have 0 parameters or more than 2";
227 }
228 }
229
230 if (createNullThing) {
231 s_matrixEffectDivide = 0;
232 s_matrixEffectWidth = 0;
233 s_matrixEffectHeight = 0;
234 s_matrixEffectBase = 0;
235 delete s_matrixEffectData;
236 s_matrixEffectData = NULL;
237 }
238
239 if (!error.empty()) {
240 fatal(error);
241 }
242
243 return !createNullThing;
244 }
245
blur_createSourceLine(byte * createLine,byte * fromLine,int overlapOnLeft,int width)246 static inline void blur_createSourceLine(byte *createLine, byte *fromLine, int overlapOnLeft, int width) {
247 int miniX;
248 memcpy(createLine + overlapOnLeft * 4, fromLine, width * 4);
249
250 for (miniX = 0; miniX < overlapOnLeft; miniX++) {
251 createLine[miniX * 4] = fromLine[0];
252 createLine[miniX * 4 + 1] = fromLine[1];
253 createLine[miniX * 4 + 2] = fromLine[2];
254 }
255
256 for (miniX = width + overlapOnLeft; miniX < width + s_matrixEffectWidth - 1; miniX++) {
257 createLine[miniX * 4] = fromLine[width * 4 - 4];
258 createLine[miniX * 4 + 1] = fromLine[width * 4 - 3];
259 createLine[miniX * 4 + 2] = fromLine[width * 4 - 2];
260 }
261 }
262
blurScreen()263 bool GraphicsManager::blurScreen() {
264 if (s_matrixEffectWidth && s_matrixEffectHeight && s_matrixEffectDivide && s_matrixEffectData) {
265 byte *thisLine;
266 int y, x;
267 bool ok = true;
268 int overlapOnLeft = s_matrixEffectWidth / 2;
269 int overlapAbove = s_matrixEffectHeight / 2;
270
271 byte **sourceLine = new byte *[s_matrixEffectHeight];
272 if (!checkNew(sourceLine))
273 return false;
274
275 for (y = 0; y < s_matrixEffectHeight; y++) {
276 sourceLine[y] = new byte[(s_matrixEffectWidth - 1 + _sceneWidth) * 4];
277 ok &= (sourceLine[y] != NULL);
278 }
279
280 if (ok) {
281 for (y = 0; y < s_matrixEffectHeight; y++) {
282 int miniY = CLIP<int>(y - overlapAbove - 1, 0, _sceneHeight - 1);
283
284 blur_createSourceLine(sourceLine[y], (byte *)_origBackdropSurface.getBasePtr(0, miniY), overlapOnLeft, _sceneWidth);
285 }
286
287 for (y = 0; y < (int)_sceneHeight; y++) {
288 thisLine = (byte *)_origBackdropSurface.getBasePtr(0, y);
289
290 //-------------------------
291 // Scroll source lines
292 //-------------------------
293 byte *tempLine = sourceLine[0];
294 for (int miniY = 0; miniY < s_matrixEffectHeight - 1; miniY++) {
295 sourceLine[miniY] = sourceLine[miniY + 1];
296 }
297 sourceLine[s_matrixEffectHeight - 1] = tempLine;
298 {
299 int h = s_matrixEffectHeight - 1;
300 int miniY = CLIP<int>(y + (s_matrixEffectHeight - overlapAbove - 1), 0, _sceneHeight - 1);
301
302 blur_createSourceLine(sourceLine[h], (byte *)_origBackdropSurface.getBasePtr(0, miniY), overlapOnLeft, _sceneWidth);
303 }
304 for (x = 0; x < (int)_sceneWidth; x++) {
305 int totalRed = 0;
306 int totalGreen = 0;
307 int totalBlue = 0;
308 int *matrixElement = s_matrixEffectData;
309 for (int miniY = 0; miniY < s_matrixEffectHeight; ++miniY) {
310 byte *pixel = &sourceLine[miniY][x * 4];
311 for (int miniX = 0; miniX < s_matrixEffectWidth; ++miniX) {
312
313 totalRed += pixel[0] **matrixElement;
314 totalGreen += pixel[1] **matrixElement;
315 totalBlue += pixel[2] **matrixElement;
316 ++matrixElement;
317 pixel += 4;
318 }
319 }
320 totalRed = (totalRed + s_matrixEffectDivide / 2) / s_matrixEffectDivide + s_matrixEffectBase;
321 totalRed = (totalRed < 0) ? 0 : ((totalRed > 255) ? 255 : totalRed);
322
323 totalGreen = (totalGreen + s_matrixEffectDivide / 2) / s_matrixEffectDivide + s_matrixEffectBase;
324 totalGreen = (totalGreen < 0) ? 0 : ((totalGreen > 255) ? 255 : totalGreen);
325
326 totalBlue = (totalBlue + s_matrixEffectDivide / 2) / s_matrixEffectDivide + s_matrixEffectBase;
327 totalBlue = (totalBlue < 0) ? 0 : ((totalBlue > 255) ? 255 : totalBlue);
328
329 *thisLine = totalRed;
330 ++thisLine;
331 *thisLine = totalGreen;
332 ++thisLine;
333 *thisLine = totalBlue;
334 ++thisLine;
335 // *thisLine = totalAlpha;
336 ++thisLine;
337 }
338 }
339 }
340
341 for (y = 0; y < s_matrixEffectHeight; y++) {
342 delete sourceLine[y];
343 }
344 delete[] sourceLine;
345 sourceLine = NULL;
346
347 return true;
348 }
349 return false;
350 }
351
352 } // End of namespace Sludge
353