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