1 | //============================================================================ |
---|---|
2 | // |
3 | // SSSS tt lll lll |
4 | // SS SS tt ll ll |
5 | // SS tttttt eeee ll ll aaaa |
6 | // SSSS tt ee ee ll ll aa |
7 | // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" |
8 | // SS SS tt ee ll ll aa aa |
9 | // SSSS ttt eeeee llll llll aaaaa |
10 | // |
11 | // Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony |
12 | // and the Stella Team |
13 | // |
14 | // See the file "License.txt" for information on usage and redistribution of |
15 | // this file, and for a DISCLAIMER OF ALL WARRANTIES. |
16 | //============================================================================ |
17 | |
18 | #include "Playfield.hxx" |
19 | #include "TIA.hxx" |
20 | |
21 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
22 | Playfield::Playfield(uInt32 collisionMask) |
23 | : myCollisionMaskDisabled(collisionMask), |
24 | myCollisionMaskEnabled(0xFFFF), |
25 | myIsSuppressed(false), |
26 | myTIA(nullptr) |
27 | { |
28 | reset(); |
29 | } |
30 | |
31 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
32 | void Playfield::reset() |
33 | { |
34 | myPattern = 0; |
35 | myReflected = false; |
36 | myRefp = false; |
37 | |
38 | myPf0 = 0; |
39 | myPf1 = 0; |
40 | myPf2 = 0; |
41 | |
42 | myX = 0; |
43 | |
44 | myObjectColor = myDebugColor = 0; |
45 | myColorLeft = myColorRight = 0; |
46 | myColorP0 = myColorP1 = 0; |
47 | myColorMode = ColorMode::normal; |
48 | myDebugEnabled = false; |
49 | |
50 | collision = 0; |
51 | |
52 | updatePattern(); |
53 | } |
54 | |
55 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
56 | void Playfield::pf0(uInt8 value) |
57 | { |
58 | if (myPf0 == value >> 4) return; |
59 | |
60 | myTIA->flushLineCache(); |
61 | |
62 | myPattern = (myPattern & 0x000FFFF0) | (value >> 4); |
63 | myPf0 = value >> 4; |
64 | |
65 | updatePattern(); |
66 | } |
67 | |
68 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
69 | void Playfield::pf1(uInt8 value) |
70 | { |
71 | if (myPf1 == value) return; |
72 | |
73 | myTIA->flushLineCache(); |
74 | |
75 | myPattern = (myPattern & 0x000FF00F) |
76 | | ((value & 0x80) >> 3) |
77 | | ((value & 0x40) >> 1) |
78 | | ((value & 0x20) << 1) |
79 | | ((value & 0x10) << 3) |
80 | | ((value & 0x08) << 5) |
81 | | ((value & 0x04) << 7) |
82 | | ((value & 0x02) << 9) |
83 | | ((value & 0x01) << 11); |
84 | |
85 | myPf1 = value; |
86 | updatePattern(); |
87 | } |
88 | |
89 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
90 | void Playfield::pf2(uInt8 value) |
91 | { |
92 | if (myPf2 == value) return; |
93 | |
94 | myTIA->flushLineCache(); |
95 | |
96 | myPattern = (myPattern & 0x00000FFF) | (value << 12); |
97 | myPf2 = value; |
98 | |
99 | updatePattern(); |
100 | } |
101 | |
102 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
103 | void Playfield::ctrlpf(uInt8 value) |
104 | { |
105 | const bool reflected = (value & 0x01) > 0; |
106 | const ColorMode colorMode = (value & 0x06) == 0x02 ? ColorMode::score : ColorMode::normal; |
107 | |
108 | if (myReflected == reflected && myColorMode == colorMode) return; |
109 | |
110 | myTIA->flushLineCache(); |
111 | |
112 | myReflected = reflected; |
113 | myColorMode = colorMode; |
114 | applyColors(); |
115 | } |
116 | |
117 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
118 | void Playfield::toggleEnabled(bool enabled) |
119 | { |
120 | myIsSuppressed = !enabled; |
121 | |
122 | updatePattern(); |
123 | } |
124 | |
125 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
126 | void Playfield::toggleCollisions(bool enabled) |
127 | { |
128 | // Only keep bit 15 active if collisions are disabled. |
129 | myCollisionMaskEnabled = enabled ? 0xFFFF : (0x8000 | myCollisionMaskDisabled); |
130 | } |
131 | |
132 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
133 | void Playfield::setColor(uInt8 color) |
134 | { |
135 | if (color != myObjectColor && myColorMode == ColorMode::normal) myTIA->flushLineCache(); |
136 | |
137 | myObjectColor = color; |
138 | applyColors(); |
139 | } |
140 | |
141 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
142 | void Playfield::setColorP0(uInt8 color) |
143 | { |
144 | if (color != myColorP0 && myColorMode == ColorMode::score) myTIA->flushLineCache(); |
145 | |
146 | myColorP0 = color; |
147 | applyColors(); |
148 | } |
149 | |
150 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
151 | void Playfield::setColorP1(uInt8 color) |
152 | { |
153 | if (color != myColorP1 && myColorMode == ColorMode::score) myTIA->flushLineCache(); |
154 | |
155 | myColorP1 = color; |
156 | applyColors(); |
157 | } |
158 | |
159 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
160 | void Playfield::setDebugColor(uInt8 color) |
161 | { |
162 | myTIA->flushLineCache(); |
163 | // allow slight luminance variations without changing color |
164 | if((color & 0xe) == 0xe) |
165 | color -= 2; |
166 | if((color & 0xe) == 0x0) |
167 | color += 2; |
168 | myDebugColor = color; |
169 | applyColors(); |
170 | } |
171 | |
172 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
173 | void Playfield::enableDebugColors(bool enabled) |
174 | { |
175 | myTIA->flushLineCache(); |
176 | myDebugEnabled = enabled; |
177 | applyColors(); |
178 | } |
179 | |
180 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
181 | void Playfield::applyColorLoss() |
182 | { |
183 | myTIA->flushLineCache(); |
184 | applyColors(); |
185 | } |
186 | |
187 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
188 | void Playfield::nextLine() |
189 | { |
190 | collision = myCollisionMaskDisabled; |
191 | } |
192 | |
193 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
194 | void Playfield::applyColors() |
195 | { |
196 | if (myDebugEnabled) |
197 | myColorLeft = myColorRight = myDebugColor; |
198 | else |
199 | { |
200 | switch (myColorMode) |
201 | { |
202 | case ColorMode::normal: |
203 | if (myTIA->colorLossActive()) |
204 | myColorLeft = myColorRight = myObjectColor |= 0x01; |
205 | else |
206 | myColorLeft = myColorRight = myObjectColor &= 0xfe; |
207 | break; |
208 | |
209 | case ColorMode::score: |
210 | if (myTIA->colorLossActive()) |
211 | { |
212 | myColorLeft = myColorP0 |= 0x01; |
213 | myColorRight = myColorP1 |= 0x01; |
214 | } |
215 | else |
216 | { |
217 | myColorLeft = myColorP0 &= 0xfe; |
218 | myColorRight = myColorP1 &= 0xfe; |
219 | } |
220 | break; |
221 | } |
222 | } |
223 | } |
224 | |
225 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
226 | uInt8 Playfield::getColor() const |
227 | { |
228 | if (!myDebugEnabled) |
229 | return myX < TIAConstants::H_PIXEL / 2 ? myColorLeft : myColorRight; |
230 | else |
231 | { |
232 | if (myX < TIAConstants::H_PIXEL / 2) |
233 | { |
234 | // left side: |
235 | if(myX < 16) |
236 | return myDebugColor - 2; // PF0 |
237 | if(myX < 48) |
238 | return myDebugColor; // PF1 |
239 | } |
240 | else |
241 | { |
242 | // right side: |
243 | if(!myReflected) |
244 | { |
245 | if(myX < TIAConstants::H_PIXEL / 2 + 16) |
246 | return myDebugColor - 2; // PF0 |
247 | if(myX < TIAConstants::H_PIXEL / 2 + 48) |
248 | return myDebugColor; // PF1 |
249 | } |
250 | else |
251 | { |
252 | if(myX >= TIAConstants::H_PIXEL - 16) |
253 | return myDebugColor - 2; // PF0 |
254 | if(myX >= TIAConstants::H_PIXEL - 48) |
255 | return myDebugColor; // PF1 |
256 | } |
257 | } |
258 | return myDebugColor + 2; // PF2 |
259 | } |
260 | } |
261 | |
262 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
263 | void Playfield::updatePattern() |
264 | { |
265 | myEffectivePattern = myIsSuppressed ? 0 : myPattern; |
266 | } |
267 | |
268 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
269 | bool Playfield::save(Serializer& out) const |
270 | { |
271 | try |
272 | { |
273 | out.putInt(collision); |
274 | out.putInt(myCollisionMaskDisabled); |
275 | out.putInt(myCollisionMaskEnabled); |
276 | |
277 | out.putBool(myIsSuppressed); |
278 | |
279 | out.putByte(myColorLeft); |
280 | out.putByte(myColorRight); |
281 | out.putByte(myColorP0); |
282 | out.putByte(myColorP1); |
283 | out.putByte(myObjectColor); |
284 | out.putByte(myDebugColor); |
285 | out.putBool(myDebugEnabled); |
286 | |
287 | out.putByte(uInt8(myColorMode)); |
288 | |
289 | out.putInt(myPattern); |
290 | out.putInt(myEffectivePattern); |
291 | out.putBool(myRefp); |
292 | out.putBool(myReflected); |
293 | |
294 | out.putByte(myPf0); |
295 | out.putByte(myPf1); |
296 | out.putByte(myPf2); |
297 | |
298 | out.putInt(myX); |
299 | } |
300 | catch(...) |
301 | { |
302 | cerr << "ERROR: TIA_Playfield::save"<< endl; |
303 | return false; |
304 | } |
305 | |
306 | return true; |
307 | } |
308 | |
309 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - |
310 | bool Playfield::load(Serializer& in) |
311 | { |
312 | try |
313 | { |
314 | collision = in.getInt(); |
315 | myCollisionMaskDisabled = in.getInt(); |
316 | myCollisionMaskEnabled = in.getInt(); |
317 | |
318 | myIsSuppressed = in.getBool(); |
319 | |
320 | myColorLeft = in.getByte(); |
321 | myColorRight = in.getByte(); |
322 | myColorP0 = in.getByte(); |
323 | myColorP1 = in.getByte(); |
324 | myObjectColor = in.getByte(); |
325 | myDebugColor = in.getByte(); |
326 | myDebugEnabled = in.getBool(); |
327 | |
328 | myColorMode = ColorMode(in.getByte()); |
329 | |
330 | myPattern = in.getInt(); |
331 | myEffectivePattern = in.getInt(); |
332 | myRefp = in.getBool(); |
333 | myReflected = in.getBool(); |
334 | |
335 | myPf0 = in.getByte(); |
336 | myPf1 = in.getByte(); |
337 | myPf2 = in.getByte(); |
338 | |
339 | myX = in.getInt(); |
340 | |
341 | applyColors(); |
342 | updatePattern(); |
343 | } |
344 | catch(...) |
345 | { |
346 | cerr << "ERROR: TIA_Playfield::load"<< endl; |
347 | return false; |
348 | } |
349 | |
350 | return true; |
351 | } |
352 |