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