Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libmeteor/source/graphics/object.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/object.hpp"
18
#include "ameteor/graphics/screen.hpp"
19
#include "../debug.hpp"
20
21
namespace AMeteor
22
{
23
namespace Graphics
24
{
25
Object::Object (uint16_t* pPalette, uint8_t* pChar) :
26
m_attr0(0),
27
m_attr1(0),
28
m_attr2(0),
29
m_width(1),
30
m_height(1),
31
m_pPalette(pPalette),
32
m_pChar(pChar),
33
m_charBegin(0x06010000),
34
m_charEnd(0x06010020)
35
{
36
}
37
38
Object::Object (const Object& obj) :
39
m_attr0(obj.m_attr0),
40
m_attr1(obj.m_attr1),
41
m_attr2(obj.m_attr2),
42
m_width(obj.m_width),
43
m_height(obj.m_height),
44
m_pPalette(obj.m_pPalette),
45
m_pChar(obj.m_pChar),
46
m_charBegin(obj.m_charBegin),
47
m_charEnd(obj.m_charEnd)
48
{
49
}
50
51
void Object::DrawLine (uint8_t line, uint32_t* surface, bool oneDim,
52
uint8_t mosaic)
53
{
54
// if the object is disabled or it's an obj window
55
if (m_attr0 & (0x1 << 9) || ((m_attr0 >> 10) & 0x3) == 2)
56
return;
57
58
// don't draw sprites with "prohibited" size
59
if (m_width == 0)
60
return;
61
62
int16_t yoff = (m_attr0 & 0xFF);
63
if (yoff > Screen::HEIGHT)
64
yoff -= 256;
65
66
// if the object does not appear on the line
67
if (yoff > line || yoff + m_height*8 <= line)
68
return;
69
70
uint8_t mosH;
71
if (m_attr0 & (0x1 << 12))
72
{
73
uint8_t mosV = mosaic >> 4;
74
mosH = mosaic & 0xF;
75
76
++mosV;
77
if (mosH) // let it be 0 if it's 0 (=> no mosaic)
78
++mosH;
79
80
line /= mosV;
81
line *= mosV;
82
}
83
else
84
mosH = 0;
85
86
int16_t xoff = (m_attr1 & 0x1FF);
87
if (xoff & (0x1 << 8))
88
xoff |= 0xFE00; // extend sign bit
89
90
uint32_t* ptr = surface + xoff;
91
92
uint32_t prio = (((uint32_t)m_attr2) << 6) & (0x3 << 16);
93
uint32_t mask = prio;
94
// if semi transparent
95
if (((m_attr0 >> 10) & 0x3) == 0x1)
96
mask |= (0x1 << 18);
97
uint8_t* pChar = m_pChar + (m_attr2 & 0x3FF) * 32;
98
bool flipH = m_attr1 & (0x1 << 12);
99
if (m_attr0 & (0x1 << 13)) // if 256 colors mode
100
{
101
// if the tile is vertically flipped
102
if (m_attr1 & (0x1 << 13))
103
{
104
// go to the tile
105
if (oneDim)
106
pChar += m_width * (8 * 8) * (m_height -1 -((line-yoff) / 8));
107
else
108
pChar += (16 * 8 * 8) * (m_height -1 -((line-yoff) / 8));
109
// advance to the right line
110
pChar += 8 * (7 - ((line-yoff) % 8));
111
}
112
else
113
{
114
// go to the tile
115
if (oneDim)
116
pChar += m_width * (8 * 8) * ((line-yoff) / 8);
117
else
118
pChar += (16 * 8 * 8) * ((line-yoff) / 8);
119
// advance to the right line
120
pChar += 8 * ((line-yoff) % 8);
121
}
122
// go to the end of the line if the object is flipped
123
if (flipH)
124
pChar += (m_width-1) * (8*8) + 8 - 1;
125
126
for (uint8_t j = 0; j < m_width*8; ++j, ++ptr)
127
{
128
// if we are on screen
129
if (ptr - surface < Screen::WIDTH && ptr >= surface)
130
{
131
if (mosH && (ptr - surface) % mosH)
132
*ptr = ptr[-1];
133
else
134
{
135
// if there is something to draw
136
if (*pChar)
137
{
138
// if we have priority or there is nothing behind
139
if (prio < (*ptr & (0x3 << 16)) || !(*ptr & 0x8000))
140
*ptr = m_pPalette[*pChar] | 0x8000 | mask;
141
}
142
// if we have nothing to draw
143
else
144
// if we have better priority
145
if (prio < (*ptr & (0x3 << 16)))
146
// we just modify priority and keep what was behind
147
*ptr = (*ptr & ~(0x3 << 16)) | (mask & (0x3 << 16));
148
}
149
}
150
151
if (flipH)
152
if ((j % 8) == 7)
153
// go to previous tile
154
pChar -= ((8*8) - (8) + 1);
155
else
156
--pChar;
157
else
158
if ((j % 8) == 7)
159
// go to next tile
160
pChar += ((8*8) - (8) + 1);
161
else
162
++pChar;
163
}
164
}
165
else
166
{
167
// if the tile is vertically flipped
168
if (m_attr1 & (0x1 << 13))
169
{
170
// go to the tile
171
if (oneDim)
172
pChar += m_width * (8 * 8 / 2) * (m_height -1 -((line-yoff) / 8));
173
else
174
pChar += (32 * 8 * 8 / 2) * (m_height -1 -((line-yoff) / 8));
175
// advance to the right line
176
pChar += (8/2) * (7 - ((line-yoff) % 8));
177
}
178
else
179
{
180
// go to the tile
181
if (oneDim)
182
pChar += m_width * (8 * 8 / 2) * ((line-yoff) / 8);
183
else
184
pChar += (32 * 8 * 8 / 2) * ((line-yoff) / 8);
185
// advance to the right line
186
pChar += (8/2) * ((line-yoff) % 8);
187
}
188
// go to the end of the line if the object is flipped
189
if (flipH)
190
pChar += (m_width-1) * (8*8/2) + 8/2 - 1;
191
192
uint16_t* pPalette = m_pPalette + 16 * (m_attr2 >> 12);
193
uint8_t colorInd;
194
for (uint8_t j = 0; j < m_width*8; ++j, ++ptr)
195
{
196
if (flipH)
197
if (j % 2)
198
{
199
colorInd = *pChar & 0xF;
200
201
if ((j % 8) == 7)
202
// go to next tile
203
// it doesn't matter if we are in one or two dimensions mapping
204
// since we never go on the next line
205
pChar -= ((8*8/2) - (8/2) + 1);
206
else
207
--pChar;
208
}
209
else
210
colorInd = *pChar >> 4;
211
else
212
if (j % 2)
213
{
214
colorInd = *pChar >> 4;
215
216
if ((j % 8) == 7)
217
// go to next tile
218
// it doesn't matter if we are in one or two dimensions mapping
219
// since we never go on the next line
220
pChar += ((8*8/2) - (8/2) + 1);
221
else
222
++pChar;
223
}
224
else
225
colorInd = *pChar & 0xF;
226
227
// if we are on screen
228
if (ptr - surface < Screen::WIDTH && ptr >= surface)
229
{
230
if (mosH && (ptr - surface) % mosH)
231
*ptr = ptr[-1];
232
else
233
{
234
// if there is something to draw
235
if (colorInd)
236
{
237
// if we have priority or there is nothing behind
238
if (prio < (*ptr & (0x3 << 16)) || !(*ptr & 0x8000))
239
*ptr = pPalette[colorInd] | 0x8000 | mask;
240
}
241
// if we have nothing to draw
242
else
243
// if we have better priority
244
if (prio < (*ptr & (0x3 << 16)))
245
// we just modify priority and keep what was behind
246
*ptr = (*ptr & ~(0x3 << 16)) | (mask & (0x3 << 16));
247
}
248
}
249
}
250
}
251
}
252
253
void Object::DrawLineRot (uint8_t line, uint32_t* surface, bool oneDim,
254
int16_t a, int16_t b, int16_t c, int16_t d, uint8_t mosaic)
255
{
256
// if it's an obj window
257
if (((m_attr0 >> 10) & 0x3) == 2)
258
return;
259
260
// don't draw sprites with "prohibited" size
261
if (m_width == 0)
262
return;
263
264
int16_t yoff = (m_attr0 & 0xFF);
265
if (yoff > Screen::HEIGHT)
266
yoff -= 256;
267
268
int16_t xoff = (m_attr1 & 0x1FF);
269
if (xoff & (0x1 << 8))
270
xoff |= 0xFE00; // extend sign bit
271
272
uint8_t fwidth = m_width*8, fheight = m_height*8;
273
if (m_attr0 & (0x1 << 9))
274
{
275
fwidth *= 2;
276
fheight *= 2;
277
}
278
279
// if the object does not appear on the line
280
if (yoff > line || yoff + fheight <= line)
281
return;
282
283
uint8_t mosH;
284
if (m_attr0 & (0x1 << 12))
285
{
286
uint8_t mosV = mosaic >> 4;
287
mosH = mosaic & 0xF;
288
289
++mosV;
290
if (mosH) // let it be 0 if it's 0 (=> no mosaic)
291
++mosH;
292
293
line /= mosV;
294
line *= mosV;
295
}
296
else
297
mosH = 0;
298
299
int32_t curX = ((m_width*8) << 8)/2
300
+ (-fwidth/2) * a + (line-yoff-fheight/2) * b;
301
int32_t curY = ((m_height*8) << 8)/2
302
+ (-fwidth/2) * c + (line-yoff-fheight/2) * d;
303
int32_t intX, intY;
304
305
uint32_t* ptr = surface + xoff;
306
307
uint32_t prio = (((uint32_t)m_attr2) << 6) & (0x3 << 16);
308
uint32_t mask = prio;
309
// if semi transparent
310
if (((m_attr0 >> 10) & 0x3) == 0x1)
311
mask |= (0x1 << 18);
312
uint8_t* pChar = m_pChar + (m_attr2 & 0x3FF) * 32;
313
uint8_t colorInd;
314
if (m_attr0 & (0x1 << 13)) // if 256 colors mode
315
{
316
for (uint8_t i = 0; i < fwidth; ++i)
317
{
318
intX = curX >> 8;
319
intY = curY >> 8;
320
321
// if we are on the object
322
if (intX >= 0 && intX < m_width*8 &&
323
intY >= 0 && intY < m_height*8 &&
324
// and we are on screen
325
ptr - surface < Screen::WIDTH && ptr >= surface)
326
{
327
if (mosH && (ptr - surface) % mosH)
328
*ptr = ptr[-1];
329
else
330
{
331
colorInd = pChar[
332
(intY/8) * (oneDim ? m_width : 16) * 8*8
333
+ (intX/8) * 8*8
334
+ (intY%8) * 8
335
+ (intX%8)];
336
337
// if there is something to draw
338
if (colorInd)
339
{
340
// if we have priority or there is nothing behind
341
if (prio < (*ptr & (0x3 << 16)) || !(*ptr & 0x8000))
342
*ptr = m_pPalette[colorInd] | 0x8000 | mask;
343
}
344
// if we have nothing to draw
345
else
346
// if we have better priority
347
if (prio < (*ptr & (0x3 << 16)))
348
// we just modify priority and keep what was behind
349
*ptr = (*ptr & ~(0x3 << 16)) | (mask & (0x3 << 16));
350
}
351
}
352
353
++ptr;
354
curX += a;
355
curY += c;
356
}
357
}
358
else
359
{
360
uint16_t* pPalette = m_pPalette + 16 * (m_attr2 >> 12);
361
for (uint8_t i = 0; i < fwidth; ++i)
362
{
363
intX = curX >> 8;
364
intY = curY >> 8;
365
366
// if we are on the object
367
if (intX >= 0 && intX < m_width*8 &&
368
intY >= 0 && intY < m_height*8 &&
369
// and we are on screen
370
ptr - surface < Screen::WIDTH && ptr >= surface)
371
{
372
if (mosH && (ptr - surface) % mosH)
373
*ptr = ptr[-1];
374
else
375
{
376
colorInd = pChar[(
377
(intY/8) * (oneDim ? m_width : 32) * 8*8
378
+ (intX/8) * 8*8
379
+ (intY%8) * 8
380
+ (intX%8)
381
) / 2];
382
383
if (intX % 2)
384
colorInd >>= 4;
385
else
386
colorInd &= 0xF;
387
388
// if there is something to draw
389
if (colorInd)
390
{
391
// if we have priority or there is nothing behind
392
if (prio < (*ptr & (0x3 << 16)) || !(*ptr & 0x8000))
393
*ptr = pPalette[colorInd] | 0x8000 | mask;
394
}
395
// if we have nothing to draw
396
else
397
// if we have better priority
398
if (prio < (*ptr & (0x3 << 16)))
399
// we just modify priority and keep what was behind
400
*ptr = (*ptr & ~(0x3 << 16)) | (mask & (0x3 << 16));
401
}
402
}
403
404
++ptr;
405
curX += a;
406
curY += c;
407
}
408
}
409
}
410
411
void Object::DrawWindow (uint8_t line, uint8_t* surface, bool oneDim,
412
uint8_t mask)
413
{
414
// if the object is disabled or it's not an obj window
415
if (m_attr0 & (0x1 << 9) || ((m_attr0 >> 10) & 0x3) != 2)
416
return;
417
418
// don't draw sprites with "prohibited" size
419
if (m_width == 0)
420
return;
421
422
int16_t yoff = (m_attr0 & 0xFF);
423
if (yoff > Screen::HEIGHT)
424
yoff -= 256;
425
426
// if the object does not appear on the line
427
if (yoff > line || yoff + m_height*8 <= line)
428
return;
429
430
int16_t xoff = (m_attr1 & 0x1FF);
431
if (xoff & (0x1 << 8))
432
xoff |= 0xFE00; // extend sign bit
433
434
bool flipH = m_attr1 & (0x1 << 12);
435
uint8_t* ptr = surface + xoff;
436
if (flipH)
437
ptr += m_width * 8 - 1;
438
uint8_t* pChar = m_pChar + (m_attr2 & 0x3FF) * 32;
439
if (m_attr0 & (0x1 << 13)) // if 256 colors mode
440
{
441
// TODO 2d map, vert flips
442
// we set pChar on the tile
443
if (oneDim)
444
pChar += m_width * (8 * 8) * ((line-yoff) / 8);
445
else
446
pChar += (16 * 8 * 8) * ((line-yoff) / 8);
447
// and we go to the first pixel we need to draw
448
pChar += 8 * ((line-yoff) % 8);
449
for (uint8_t j = 0; j < m_width*8; ++j)
450
{
451
if (ptr - surface < Screen::WIDTH && ptr >= surface && *pChar)
452
*ptr = mask;
453
454
if (flipH)
455
--ptr;
456
else
457
++ptr;
458
459
if ((j % 8) == 7)
460
// go to next tile
461
pChar += ((8*8) - (8) + 1);
462
else
463
++pChar;
464
}
465
}
466
else
467
{
468
// TODO verts flips
469
// we set pChar on the tile
470
if (oneDim)
471
pChar += m_width * (8 * 8 / 2) * ((line-yoff) / 8);
472
else
473
pChar += (32 * 8 * 8 / 2) * ((line-yoff) / 8);
474
// and we go to the first pixel we need to draw
475
pChar += (8/2) * ((line-yoff) % 8);
476
uint8_t colorInd;
477
for (uint8_t j = 0; j < m_width*8; ++j)
478
{
479
if (j % 2)
480
{
481
colorInd = *pChar >> 4;
482
483
if ((j % 8) == 7)
484
// go to next tile
485
// it doesn't matter if we are in one or two dimensions mapping
486
// since we never go on the next line
487
pChar += ((8*8/2) - (8/2) + 1);
488
else
489
++pChar;
490
}
491
else
492
colorInd = *pChar & 0xF;
493
494
// if we are not offscreen and there is a color
495
if (ptr - surface < Screen::WIDTH && ptr >= surface && colorInd)
496
*ptr = mask;
497
498
if (flipH)
499
--ptr;
500
else
501
++ptr;
502
}
503
}
504
}
505
506
void Object::DrawWindowRot (uint8_t line, uint8_t* surface,
507
bool oneDim, int16_t a, int16_t b, int16_t c, int16_t d, uint8_t mask)
508
{
509
// if it's not an obj window
510
if (((m_attr0 >> 10) & 0x3) != 2)
511
return;
512
513
// don't draw sprites with "prohibited" size
514
if (m_width == 0)
515
return;
516
517
int16_t yoff = (m_attr0 & 0xFF);
518
if (yoff > Screen::HEIGHT)
519
yoff -= 256;
520
521
int16_t xoff = (m_attr1 & 0x1FF);
522
if (xoff & (0x1 << 8))
523
xoff |= 0xFE00; // extend sign bit
524
525
uint8_t fwidth = m_width*8, fheight = m_height*8;
526
if (m_attr0 & (0x1 << 9))
527
{
528
fwidth *= 2;
529
fheight *= 2;
530
}
531
532
// if the object does not appear on the line
533
if (yoff > line || yoff + fheight <= line)
534
return;
535
536
int32_t curX = ((m_width*8) << 8)/2
537
+ (-fwidth/2) * a + (line-yoff-fheight/2) * b;
538
int32_t curY = ((m_height*8) << 8)/2
539
+ (-fwidth/2) * c + (line-yoff-fheight/2) * d;
540
int32_t intX, intY;
541
542
uint8_t* ptr = surface + xoff;
543
uint8_t* pChar = m_pChar + (m_attr2 & 0x3FF) * 32;
544
uint8_t colorInd;
545
if (m_attr0 & (0x1 << 13)) // if 256 colors mode
546
{
547
for (uint8_t i = 0; i < fwidth; ++i)
548
{
549
intX = curX >> 8;
550
intY = curY >> 8;
551
552
if (intX >= 0 && intX < m_width*8 &&
553
intY >= 0 && intY < m_height*8)
554
{
555
colorInd = pChar[
556
(intY/8) * (oneDim ? m_width : 32) * 8*8
557
+ (intX/8) * 8*8
558
+ (intY%8) * 8
559
+ (intX%8)];
560
561
if (ptr - surface < Screen::WIDTH && ptr >= surface && colorInd)
562
*ptr = mask;
563
}
564
565
++ptr;
566
curX += a;
567
curY += c;
568
}
569
}
570
else
571
{
572
for (uint8_t i = 0; i < fwidth; ++i)
573
{
574
intX = curX >> 8;
575
intY = curY >> 8;
576
577
if (intX >= 0 && intX < m_width*8 &&
578
intY >= 0 && intY < m_height*8)
579
{
580
colorInd = pChar[(
581
(intY/8) * (oneDim ? m_width : 32) * 8*8
582
+ (intX/8) * 8*8
583
+ (intY%8) * 8
584
+ (intX%8)
585
) / 2];
586
587
if (intX % 2)
588
colorInd >>= 4;
589
else
590
colorInd &= 0xF;
591
592
if (ptr - surface < Screen::WIDTH && ptr >= surface && colorInd)
593
*ptr = mask;
594
}
595
596
++ptr;
597
curX += a;
598
curY += c;
599
}
600
}
601
}
602
603
604
void Object::UpdateAttrs (uint16_t attr0, uint16_t attr1, uint16_t attr2)
605
{
606
bool setsize = false, reload = false;
607
if ((m_attr0 & 0xFF00) != (attr0 & 0xFF00))
608
{
609
reload = true;
610
setsize = true;
611
}
612
m_attr0 = attr0;
613
614
if ((m_attr1 & 0xF000) != (attr1 & 0xF000))
615
{
616
reload = true;
617
setsize = true;
618
}
619
m_attr1 = attr1;
620
621
if ((m_attr2 & 0xF1FF) != (attr2 & 0xF1FF))
622
reload = true;
623
m_attr2 = attr2;
624
625
if (setsize)
626
{
627
SetSize();
628
629
if (reload)
630
{
631
m_charBegin = 0x06010000 + (m_attr2 & 0x3FF)*32;
632
m_charEnd = m_charBegin + m_width*m_height*8*
633
((m_attr0 & (0x1 << 13)) ? 8 : 4);
634
}
635
}
636
}
637
638
void Object::UpdateAttr0 (uint16_t attr0)
639
{
640
// FIXME : we can do a more restrictive condition
641
if ((m_attr0 & 0xFF00) != (attr0 & 0xFF00))
642
{
643
m_attr0 = attr0;
644
SetSize();
645
m_charEnd = m_charBegin + m_width*m_height*8*
646
((m_attr0 & (0x1 << 13)) ? 8 : 4);
647
}
648
else
649
m_attr0 = attr0;
650
}
651
652
void Object::UpdateAttr1 (uint16_t attr1)
653
{
654
// if the size has changed
655
if ((m_attr1 & 0xC000) != (attr1 & 0xC000))
656
{
657
m_attr1 = attr1;
658
SetSize();
659
m_charEnd = m_charBegin + m_width*m_height*8*
660
((m_attr0 & (0x1 << 13)) ? 8 : 4);
661
}
662
else
663
m_attr1 = attr1;
664
}
665
666
void Object::UpdateAttr2 (uint16_t attr2)
667
{
668
if ((m_attr2 & 0xF1FF) != (attr2 & 0xF1FF))
669
{
670
m_attr2 = attr2;
671
m_charBegin = 0x06010000 + (m_attr2 & 0x3FF)*32;
672
m_charEnd = m_charBegin + m_width*m_height*8*
673
((m_attr0 & (0x1 << 13)) ? 8 : 4);
674
}
675
else
676
m_attr2 = attr2;
677
}
678
679
inline void Object::SetSize ()
680
{
681
static const uint8_t Width[4][4] = {
682
{1, 2, 4, 8}, // Square
683
{2, 4, 4, 8}, // Horizontal
684
{1, 1, 2, 4}, // Vertical
685
{0, 0, 0, 0} // Prohibited
686
};
687
static const uint8_t Height[4][4] = {
688
{1, 2, 4, 8}, // Square
689
{1, 1, 2, 4}, // Horizontal
690
{2, 4, 4, 8}, // Vertical
691
{0, 0, 0, 0} // Prohibited
692
};
693
694
m_width = Width[m_attr0 >> 14][m_attr1 >> 14];
695
m_height = Height[m_attr0 >> 14][m_attr1 >> 14];
696
}
697
}
698
}
699
700