Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libmeteor/source/graphics/bglayer.cpp
2 views
1
// Meteor - A Nintendo Gameboy Advance emulator
2
// Copyright (C) 2009-2011 Philippe Daouadi
3
//
4
// This program is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// This program is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with this program. If not, see <http://www.gnu.org/licenses/>.
16
17
#include "ameteor/graphics/bglayer.hpp"
18
#include "ameteor/graphics/screen.hpp"
19
#include "../debug.hpp"
20
21
namespace AMeteor
22
{
23
namespace Graphics
24
{
25
BgLayer::BgLayer (int8_t num, Memory& memory, Io& io, uint16_t* pPalette) :
26
m_memory(memory),
27
m_io(io),
28
m_num(num),
29
m_priority(0),
30
m_cnt(0),
31
m_xoff(0),
32
m_yoff(0),
33
m_tWidth(32),
34
m_tHeight(32),
35
m_rWidth(16),
36
m_rHeight(16),
37
m_mapAdd(0x06000000),
38
m_charAdd(0x06000000),
39
m_pPalette(pPalette)
40
{
41
}
42
43
BgLayer::~BgLayer ()
44
{
45
}
46
47
void BgLayer::DrawLine0 (uint8_t line, uint16_t* ptr)
48
{
49
uint8_t mosH;
50
if (m_cnt & (0x1 << 6))
51
{
52
mosH = m_io.DRead8(Io::MOSAIC);
53
uint8_t mosV = mosH >> 4;
54
mosH &= 0x0F;
55
56
++mosV;
57
if (mosH) // let it be 0 if it's 0 (=> no mosaic)
58
++mosH;
59
60
line /= mosV;
61
line *= mosV;
62
}
63
else
64
mosH = 0;
65
66
uint16_t* pMap = (uint16_t*)m_memory.GetRealAddress(m_mapAdd), *pTile;
67
uint8_t* pChar = m_memory.GetRealAddress(m_charAdd), *tpChar;
68
uint8_t i = 0;
69
70
// theses are the coordinates on the layer from which we will draw a line
71
uint16_t xoff = m_xoff % (m_tWidth * 8);
72
uint16_t yoff = (m_yoff + line) % (m_tHeight * 8);
73
74
// theses are the coordinates on the tile of the pixels we are drawing
75
// NOTE : if the tile is horizontally flipped tileX = 8 - tileX, thus
76
// when we draw it is ALWAYS incremented no matter how the tile is
77
// flipped
78
// NOTE : tileY is NOT redefined if the tile is flipped vertically
79
int8_t tileX = xoff % 8, tileY;
80
bool flipH;
81
82
// sets pTile to the tile we must draw first
83
// +---+---+
84
// | 1 | 2 |
85
// +---+---+
86
// | 3 | 4 |
87
// +---+---+
88
if (yoff >= 256)
89
if (m_tWidth == 64)
90
if (xoff >= 256)
91
// zone 4
92
pTile = pMap + 32*32 + 32*32 + 32*32
93
+ 32 * ((yoff-256)/8) + (xoff-256)/8;
94
else
95
// zone 3 (large map)
96
pTile = pMap + 32*32 + 32*32 + 32 * ((yoff-256)/8) + xoff/8;
97
else
98
// zone 3 (no large map)
99
pTile = pMap + 32*32 + 32 * ((yoff-256)/8) + xoff/8;
100
else
101
if (xoff >= 256)
102
// zone 2
103
pTile = pMap + 32*32 + 32 * (yoff/8) + (xoff-256)/8;
104
else
105
// zone 1
106
pTile = pMap + 32 * (yoff/8) + xoff/8;
107
108
if (m_hicolor)
109
{
110
while (i < 240)
111
{
112
flipH = (bool)(*pTile & (0x1 << 10));
113
114
// if the tile is vertically fliped
115
if (*pTile & (0x1 << 11))
116
tileY = 7 - (yoff % 8);
117
else
118
tileY = yoff % 8;
119
120
if (flipH)
121
tpChar = pChar + (*pTile & 0x3FF)*8*8 + tileY*8 + 7 - tileX;
122
else
123
tpChar = pChar + (*pTile & 0x3FF)*8*8 + tileY*8 + tileX;
124
125
while (tileX < 8)
126
{
127
if (mosH && i % mosH)
128
*ptr = ptr[-1];
129
else
130
{
131
if (*tpChar)
132
*ptr = m_pPalette[*tpChar] | 0x8000;
133
else
134
*ptr = 0x0;
135
}
136
if (flipH)
137
--tpChar;
138
else
139
++tpChar;
140
141
++ptr;
142
++tileX;
143
++i;
144
145
if (i == 240)
146
return;
147
}
148
tileX = 0;
149
++pTile;
150
151
// support for big maps and wrap around
152
if (!((pTile - pMap) % 32))
153
if (m_tWidth == 32)
154
pTile -= 32;
155
else
156
if (yoff >= 256 && pTile - pMap > 32*32 * 3
157
|| yoff < 256 && pTile - pMap > 32*32)
158
pTile -= 32*33;
159
else
160
pTile += 32*31;
161
}
162
}
163
else
164
{
165
uint16_t* pPalette;
166
uint8_t colorInd;
167
168
// for each pixel of the line we are drawing
169
while (i < 240)
170
{
171
pPalette = m_pPalette + ((*pTile >> 12) & 0xF) * 16;
172
flipH = (bool)(*pTile & (0x1 << 10));
173
174
// if the tile is vertically fliped
175
if (*pTile & (0x1 << 11))
176
tileY = 7 - (yoff % 8);
177
else
178
tileY = yoff % 8;
179
180
if (flipH)
181
tpChar = pChar + ((*pTile & 0x3FF)*8*8 + tileY*8 + 7 - tileX)/2;
182
else
183
tpChar = pChar + ((*pTile & 0x3FF)*8*8 + tileY*8 + tileX)/2;
184
185
// we draw until the end of the tile or the line
186
while (tileX < 8)
187
{
188
if (flipH)
189
if (tileX % 2)
190
{
191
colorInd = *tpChar & 0xF;
192
--tpChar;
193
}
194
else
195
colorInd = *tpChar >> 4;
196
else
197
if (tileX % 2)
198
{
199
colorInd = *tpChar >> 4;
200
++tpChar;
201
}
202
else
203
colorInd = *tpChar & 0xF;
204
205
if (mosH && i % mosH)
206
*ptr = ptr[-1];
207
else
208
{
209
if (colorInd)
210
*ptr = pPalette[colorInd] | 0x8000;
211
else
212
*ptr = 0x0;
213
}
214
215
++ptr;
216
++tileX;
217
++i;
218
219
// if this was the last pixel of the line
220
if (i == 240)
221
return;
222
}
223
224
// we have finished drawing a tile, so we go to the next tile
225
tileX = 0;
226
++pTile;
227
228
// support for big maps and wrap around
229
if (!((pTile - pMap) % 32))
230
if (m_tWidth == 32)
231
pTile -= 32;
232
else
233
if (yoff >= 256 && pTile - pMap > 32*32 * 3
234
|| yoff < 256 && pTile - pMap > 32*32)
235
pTile -= 32*33;
236
else
237
pTile += 32*31;
238
}
239
}
240
}
241
242
void BgLayer::DrawLine2 (uint16_t* ptr,
243
int32_t curX, int32_t curY,
244
int16_t dx, int16_t dy)
245
{
246
if (!m_hicolor)
247
{
248
//FIXME is this possible ??
249
//this seems to be impossible, but we should not crash since some games
250
//do it
251
//puts("rotated layer with 16 colors");
252
//abort();
253
// XXX
254
//it seems now that we should not care about this flag, we draw in 256
255
//colors, that's all
256
//return;
257
}
258
int32_t intX, intY;
259
260
uint16_t colorInd;
261
262
uint8_t* pMap = (uint8_t*)m_memory.GetRealAddress(m_mapAdd);
263
uint8_t* pChar = m_memory.GetRealAddress(m_charAdd);
264
265
for (uint8_t x = 0; x < 240; ++x, ++ptr, curX += dx, curY += dy)
266
{
267
intX = curX >> 8;
268
intY = curY >> 8;
269
270
// if we are off layer
271
if (intX < 0 || intX >= m_rWidth*8)
272
if (m_cnt & (0x1 << 13))
273
{
274
// NOTE : in C++, the modulus can be negative, this is because in
275
// x86, the IDIV instruction gives a remainder of the same sign of
276
// the dividend
277
curX %= m_rWidth*8 << 8;
278
if (curX < 0)
279
curX += m_rWidth*8 << 8;
280
intX = curX >> 8;
281
}
282
else
283
continue;
284
if (intY < 0 || intY >= m_rHeight*8)
285
if (m_cnt & (0x1 << 13))
286
{
287
curY %= m_rHeight*8 << 8;
288
if (curY < 0)
289
curY += m_rHeight*8 << 8;
290
intY = curY >> 8;
291
}
292
else
293
continue;
294
295
colorInd = pChar[pMap[intY / 8 * m_rWidth + intX / 8] * 8 * 8
296
+ (intY % 8) * 8 + intX % 8];
297
298
if (colorInd)
299
*ptr = m_pPalette[colorInd] | 0x8000;
300
else
301
*ptr = 0x0;
302
}
303
}
304
305
void BgLayer::DrawLine3 (uint16_t* ptr,
306
int32_t curX, int32_t curY,
307
int16_t dx, int16_t dy)
308
{
309
int32_t intX, intY;
310
311
uint16_t* pChar = (uint16_t*) m_memory.GetRealAddress(0x06000000);
312
313
for (uint8_t x = 0; x < 240; ++x, ++ptr, curX += dx, curY += dy)
314
{
315
intX = curX >> 8;
316
intY = curY >> 8;
317
318
// if we are off layer
319
if (intX < 0 || intX >= 240)
320
/*
321
if (m_cnt & (0x1 << 13))
322
{
323
// NOTE : in C++, the modulus can be negative
324
intX %= 240;
325
if (intX < 0)
326
intX += 240;
327
}
328
else*/
329
continue;
330
if (intY < 0 || intY >= 160)
331
/*
332
if (m_cnt & (0x1 << 13))
333
{
334
intY %= 160;
335
if (intY < 0)
336
intY += 160;
337
}
338
else*/
339
continue;
340
341
*ptr = pChar[intY * 240 + intX] | 0x8000;
342
}
343
}
344
345
void BgLayer::DrawLine4 (uint8_t line, uint16_t* ptr,
346
int32_t curX, int32_t curY,
347
int16_t dx, int16_t dmx, int16_t dy, int16_t dmy, bool frame1)
348
{
349
uint8_t mosH;
350
if (m_cnt & (0x1 << 6))
351
{
352
// TODO horizontal mosaic not implemented
353
mosH = m_io.DRead8(Io::MOSAIC);
354
uint8_t mosV = mosH >> 4;
355
mosH &= 0x0F;
356
357
++mosV;
358
if (mosH) // let it be 0 if it's 0 (=> no mosaic)
359
++mosH;
360
361
uint8_t back = line % mosV;
362
363
curX -= back*dmx;
364
curY -= back*dmy;
365
}
366
else
367
mosH = 0;
368
369
int32_t intX, intY;
370
371
uint16_t colorInd;
372
373
uint8_t* pChar =
374
m_memory.GetRealAddress(frame1 ? 0x0600A000 : 0x06000000);
375
376
for (uint8_t x = 0; x < 240; ++x, ++ptr, curX += dx, curY += dy)
377
{
378
if (mosH && x % mosH)
379
{
380
*ptr = ptr[-1];
381
continue;
382
}
383
384
intX = curX >> 8;
385
intY = curY >> 8;
386
387
// if we are off layer
388
if (intX < 0 || intX >= 240)
389
if (m_cnt & (0x1 << 13))
390
{
391
// NOTE : in C++, the modulus can be negative
392
intX %= 240;
393
if (intX < 0)
394
intX += 240;
395
}
396
else
397
continue;
398
if (intY < 0 || intY >= 160)
399
if (m_cnt & (0x1 << 13))
400
{
401
intY %= 160;
402
if (intY < 0)
403
intY += 160;
404
}
405
else
406
continue;
407
408
colorInd = pChar[intY * 240 + intX];
409
410
if (colorInd)
411
*ptr = m_pPalette[colorInd] | 0x8000;
412
else
413
*ptr = 0x0;
414
}
415
}
416
417
void BgLayer::DrawLine5 (uint16_t* ptr,
418
int32_t curX, int32_t curY,
419
int16_t dx, int16_t dy, bool frame1)
420
{
421
int32_t intX, intY;
422
423
uint16_t* pChar = (uint16_t*) m_memory.GetRealAddress(frame1 ? 0x0600A000 : 0x06000000);
424
425
for (uint8_t x = 0; x < 240; ++x, ++ptr, curX += dx, curY += dy)
426
{
427
intX = curX >> 8;
428
intY = curY >> 8;
429
430
// if we are off layer
431
if (intX < 0 || intX >= 160)
432
continue;
433
if (intY < 0 || intY >= 128)
434
continue;
435
436
*ptr = pChar[intY * 160 + intX] | 0x8000;
437
}
438
}
439
440
void BgLayer::UpdateCnt (uint16_t cnt)
441
{
442
if (m_cnt == cnt)
443
return;
444
445
switch (cnt >> 14)
446
{
447
case 0:
448
m_tWidth = m_tHeight = 32;
449
m_rWidth = m_rHeight = 16;
450
break;
451
case 1:
452
m_tWidth = 64;
453
m_tHeight = 32;
454
m_rWidth = m_rHeight = 32;
455
break;
456
case 2:
457
m_tWidth = 32;
458
m_tHeight = 64;
459
m_rWidth = m_rHeight = 64;
460
break;
461
case 3:
462
m_tWidth = m_tHeight = 64;
463
m_rWidth = m_rHeight = 128;
464
break;
465
}
466
467
m_priority = (cnt & 0x3);
468
m_charAdd = 0x06000000 + ((cnt >> 2) & 0x3) * 0x4000;
469
m_hicolor = cnt & (0x1 << 7);
470
m_mapAdd = 0x06000000 + ((cnt >> 8) & 0x1F) * 0x0800;
471
472
m_cnt = cnt;
473
}
474
}
475
}
476
477