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 "bladerunner/screen_effects.h"
24 
25 #include "common/stream.h"
26 
27 namespace BladeRunner {
28 
ScreenEffects(BladeRunnerEngine * vm,int size)29 ScreenEffects::ScreenEffects(BladeRunnerEngine *vm, int size) {
30 	_vm = vm;
31 	_dataSize = size;
32 	_data = new uint8[size];
33 	_entries.reserve(kMaxEffectsInScene + 1);
34 }
35 
~ScreenEffects()36 ScreenEffects::~ScreenEffects() {
37 	delete[] _data;
38 #if BLADERUNNER_ORIGINAL_BUGS
39 #else
40 	if (!_skipEntries.empty()) {
41 		_skipEntries.clear();
42 	}
43 #endif // BLADERUNNER_ORIGINAL_BUGS
44 }
45 
46 #if BLADERUNNER_ORIGINAL_BUGS
47 #else
toggleEntry(int effectId,bool skip)48 void ScreenEffects::toggleEntry(int effectId, bool skip) {
49 	if (effectId >= 0 && effectId < kMaxEffectsInScene) {
50 		int foundAt = -1;
51 		for (int i = 0; i < (int)_skipEntries.size(); ++i) {
52 			if (_skipEntries[i] == effectId) {
53 				foundAt = i;
54 				break;
55 			}
56 		}
57 
58 		if (skip && foundAt < 0) {
59 			int newSlot = 0;
60 			// keep the array sorted (from greater values to lower values)
61 			for (int i = 0; i < (int)_skipEntries.size(); ++i) {
62 				if (effectId > _skipEntries[i]) {
63 					newSlot = i;
64 					break;
65 				}
66 			}
67 			_skipEntries.insert_at(newSlot, effectId);
68 		} else if (!skip && foundAt >= 0 ) {
69 			_skipEntries.remove_at(foundAt);
70 		}
71 	} else if (effectId == -1 && !skip) {
72 		_skipEntries.clear();
73 	}
74 }
75 #endif // BLADERUNNER_ORIGINAL_BUGS
76 
readVqa(Common::SeekableReadStream * stream)77 void ScreenEffects::readVqa(Common::SeekableReadStream *stream) {
78 	uint8 *dataPtr = _data;
79 	int dataSize   = _dataSize;
80 
81 	int entryCount = stream->readUint32LE();
82 
83 	if (entryCount == 0) {
84 		return;
85 	}
86 
87 	entryCount = MIN(entryCount, kMaxEffectsInScene);
88 	_entries.resize(entryCount);
89 
90 	for (Common::Array<Entry>::iterator entry = _entries.begin(); entry != _entries.end(); ++entry) {
91 		stream->read(&entry->palette, sizeof(Color256) * 16);
92 
93 		entry->x      = stream->readUint16LE();
94 		entry->y      = stream->readUint16LE();
95 		entry->width  = stream->readUint16LE();
96 		entry->height = stream->readUint16LE();
97 		entry->z      = stream->readUint16LE();
98 
99 		int entryDataSize = stream->readUint16LE();
100 
101 		int pixelCount = entry->width * entry->height;
102 
103 		if (pixelCount > dataSize) { // too big to fit
104 			entry->width = 0;
105 			entry->height = 0;
106 			entry->data = _data;
107 			continue;
108 			// TODO a bug? there is a issue in the game code, because it's not skipping data of entry in this case
109 		}
110 
111 		int pos = stream->pos();
112 		dataSize -= pixelCount;
113 		entry->data = dataPtr;
114 		do {
115 			uint8 count = stream->readByte();
116 			if (count & 0x80) { // repeat same data
117 				uint8 colors = stream->readByte();
118 				for (uint8 j = 0; j < (count & 0x7F) + 1; ++j) {
119 					*(dataPtr++) = colors >> 4;  // upper 4 bit
120 					*(dataPtr++) = colors & 0xF; // lower 4 bit
121 					pixelCount -= 2;
122 				}
123 			} else { // copy data
124 				for (uint8 j = 0; j < count + 1; ++j) {
125 					uint8 colors = stream->readByte();
126 					*(dataPtr++) = colors >> 4;  // upper 4 bit
127 					*(dataPtr++) = colors & 0xF; // lower 4 bit
128 					pixelCount -= 2;
129 				}
130 			}
131 		} while (pixelCount > 0);
132 		stream->seek(pos + entryDataSize, SEEK_SET);
133 	}
134 
135 #if BLADERUNNER_ORIGINAL_BUGS
136 #else
137 	// added code to allow skipping specific effects
138 	for (int i = 0; i < (int)_skipEntries.size(); ++i) {
139 		_entries.remove_at(_skipEntries[i]);
140 	}
141 #endif // BLADERUNNER_ORIGINAL_BUGS
142 }
143 
144 //TODO:
145 //bool ScreenEffects::isAffectingArea(int x, int y, int width, int height, int z) {
146 //	int xx = x >> 1;
147 //	int yy = y >> 1;
148 //	if (_entries.empty()) {
149 //		return false;
150 //	}
151 //
152 //	for(int i = 0; i < _entries.size(); ++i) {
153 //		Entry &entry = _entries[i];
154 //		if (entry.z < z) {
155 //			if (entry.width < (width >> 1) + xx) {
156 //				if (entry.width + entry.x > xx) {
157 //					if (entry.height < (height >> 1) + yy) {
158 //						if (entry.height + entry.y > yy) {
159 //							return true;
160 //						}
161 //					}
162 //				}
163 //			}
164 //		}
165 //	}
166 //	return false;
167 //}
168 
getColor(Color256 * outColor,uint16 x,uint16 y,uint16 z) const169 void ScreenEffects::getColor(Color256 *outColor, uint16 x, uint16 y, uint16 z) const {
170 	Color256 color = { 0, 0, 0 };
171 	for (Common::Array<const Entry>::iterator entry = _entries.begin(); entry != _entries.end(); ++entry) {
172 		uint16 x1 = (x / 2) - entry->x;
173 		uint16 y1 = (y / 2) - entry->y;
174 		if (x1 < entry->width && y1 < entry->height && z > entry->z) {
175 			int colorIndex = entry->data[y1 * entry->width + x1];
176 			Color256 entryColor = entry->palette[colorIndex];
177 			color.r += entryColor.r;
178 			color.g += entryColor.g;
179 			color.b += entryColor.b;
180 		}
181 	}
182 	*outColor = color;
183 }
184 
185 } // End of namespace BladeRunner
186