1 // VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
2 // Copyright (C) 1999-2003 Forgotten
3 // Copyright (C) 2004 Forgotten and the VBA development team
4
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 2, or(at your option)
8 // any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 #include <memory.h>
20
21 #include "../GBA.h"
22 #include "gbGlobals.h"
23 #include "gbSGB.h"
24
25 u8 gbInvertTab[256] = {
26 0x00,0x80,0x40,0xc0,0x20,0xa0,0x60,0xe0,
27 0x10,0x90,0x50,0xd0,0x30,0xb0,0x70,0xf0,
28 0x08,0x88,0x48,0xc8,0x28,0xa8,0x68,0xe8,
29 0x18,0x98,0x58,0xd8,0x38,0xb8,0x78,0xf8,
30 0x04,0x84,0x44,0xc4,0x24,0xa4,0x64,0xe4,
31 0x14,0x94,0x54,0xd4,0x34,0xb4,0x74,0xf4,
32 0x0c,0x8c,0x4c,0xcc,0x2c,0xac,0x6c,0xec,
33 0x1c,0x9c,0x5c,0xdc,0x3c,0xbc,0x7c,0xfc,
34 0x02,0x82,0x42,0xc2,0x22,0xa2,0x62,0xe2,
35 0x12,0x92,0x52,0xd2,0x32,0xb2,0x72,0xf2,
36 0x0a,0x8a,0x4a,0xca,0x2a,0xaa,0x6a,0xea,
37 0x1a,0x9a,0x5a,0xda,0x3a,0xba,0x7a,0xfa,
38 0x06,0x86,0x46,0xc6,0x26,0xa6,0x66,0xe6,
39 0x16,0x96,0x56,0xd6,0x36,0xb6,0x76,0xf6,
40 0x0e,0x8e,0x4e,0xce,0x2e,0xae,0x6e,0xee,
41 0x1e,0x9e,0x5e,0xde,0x3e,0xbe,0x7e,0xfe,
42 0x01,0x81,0x41,0xc1,0x21,0xa1,0x61,0xe1,
43 0x11,0x91,0x51,0xd1,0x31,0xb1,0x71,0xf1,
44 0x09,0x89,0x49,0xc9,0x29,0xa9,0x69,0xe9,
45 0x19,0x99,0x59,0xd9,0x39,0xb9,0x79,0xf9,
46 0x05,0x85,0x45,0xc5,0x25,0xa5,0x65,0xe5,
47 0x15,0x95,0x55,0xd5,0x35,0xb5,0x75,0xf5,
48 0x0d,0x8d,0x4d,0xcd,0x2d,0xad,0x6d,0xed,
49 0x1d,0x9d,0x5d,0xdd,0x3d,0xbd,0x7d,0xfd,
50 0x03,0x83,0x43,0xc3,0x23,0xa3,0x63,0xe3,
51 0x13,0x93,0x53,0xd3,0x33,0xb3,0x73,0xf3,
52 0x0b,0x8b,0x4b,0xcb,0x2b,0xab,0x6b,0xeb,
53 0x1b,0x9b,0x5b,0xdb,0x3b,0xbb,0x7b,0xfb,
54 0x07,0x87,0x47,0xc7,0x27,0xa7,0x67,0xe7,
55 0x17,0x97,0x57,0xd7,0x37,0xb7,0x77,0xf7,
56 0x0f,0x8f,0x4f,0xcf,0x2f,0xaf,0x6f,0xef,
57 0x1f,0x9f,0x5f,0xdf,0x3f,0xbf,0x7f,0xff
58 };
59
60 u16 gbLineMix[160];
61
gbRenderLine()62 void gbRenderLine()
63 {
64 u8 * bank0;
65 u8 * bank1;
66 if(gbCgbMode) {
67 bank0 = &gbVram[0x0000];
68 bank1 = &gbVram[0x2000];
69 } else {
70 bank0 = &gbMemory[0x8000];
71 bank1 = NULL;
72 }
73
74 int tile_map = 0x1800;
75 if((register_LCDC & 8) != 0)
76 tile_map = 0x1c00;
77
78 int tile_pattern = 0x0800;
79
80 if((register_LCDC & 16) != 0)
81 tile_pattern = 0x0000;
82
83 int x = 0;
84 int y = register_LY;
85
86 if(y >= 144)
87 return;
88
89 // int yLine = (y + gbBorderRowSkip) * gbBorderLineSkip;
90
91 int sx = register_SCX;
92 int sy = register_SCY;
93
94 sy+=y;
95
96 sy &= 255;
97
98 int tx = sx >> 3;
99 int ty = sy >> 3;
100
101 int bx = 1 << (7 - (sx & 7));
102 int by = sy & 7;
103
104 int tile_map_line_y = tile_map + ty * 32;
105
106 int tile_map_address = tile_map_line_y + tx;
107
108 u8 attrs = 0;
109 if(bank1 != NULL)
110 attrs = bank1[tile_map_address];
111
112 u8 tile = bank0[tile_map_address];
113
114 tile_map_address++;
115
116 if((register_LCDC & 16) == 0) {
117 if(tile < 128) tile += 128;
118 else tile -= 128;
119 }
120
121 int tile_pattern_address = tile_pattern + tile * 16 + by*2;
122
123 if(register_LCDC & 0x80) {
124 if((register_LCDC & 0x01 || gbCgbMode) && (layerSettings & 0x0100)) {
125 while(x < 160) {
126 u8 tile_a = 0;
127 u8 tile_b = 0;
128
129 if(attrs & 0x40) {
130 tile_pattern_address = tile_pattern + tile * 16 + (7-by)*2;
131 }
132
133 if(attrs & 0x08) {
134 tile_a = bank1[tile_pattern_address++];
135 tile_b = bank1[tile_pattern_address];
136 } else {
137 tile_a = bank0[tile_pattern_address++];
138 tile_b = bank0[tile_pattern_address];
139 }
140
141 if(attrs & 0x20) {
142 tile_a = gbInvertTab[tile_a];
143 tile_b = gbInvertTab[tile_b];
144 }
145
146 while(bx > 0) {
147 u8 c = (tile_a & bx) ? 1 : 0;
148 c += ((tile_b & bx) ? 2 : 0);
149
150 gbLineBuffer[x] = c; // mark the gbLineBuffer color
151
152 if(attrs & 0x80)
153 gbLineBuffer[x] |= 0x300;
154
155 if(gbCgbMode) {
156 c = c + (attrs & 7)*4;
157 } else {
158 c = gbBgp[c];
159 if(gbSgbMode && !gbCgbMode) {
160 int dx = x >> 3;
161 int dy = y >> 3;
162
163 int palette = gbSgbATF[dy * 20 + dx];
164
165 if(c == 0)
166 palette = 0;
167
168 c = c + 4*palette;
169 }
170 }
171 gbLineMix[x] = gbColorOption ? gbColorFilter[gbPalette[c]] :
172 gbPalette[c];
173 x++;
174 if(x >= 160)
175 break;
176 bx >>= 1;
177 }
178 tx++;
179 if(tx == 32)
180 tx = 0;
181 bx = 128;
182
183 if(bank1)
184 attrs = bank1[tile_map_line_y + tx];
185
186 tile = bank0[tile_map_line_y + tx];
187
188 if((register_LCDC & 16) == 0) {
189 if(tile < 128) tile += 128;
190 else tile -= 128;
191 }
192 tile_pattern_address = tile_pattern + tile * 16 + by * 2;
193 }
194 } else {
195 for(int i = 0; i < 160; i++) {
196 gbLineMix[i] = gbPalette[0];
197 gbLineBuffer[i] = 0;
198 }
199 }
200
201 // do the window display
202 if((register_LCDC & 0x20) && (layerSettings & 0x2000)) {
203 int wy = register_WY;
204
205 if(y >= wy) {
206 int wx = register_WX;
207 wx -= 7;
208
209 if( wx <= 159 && gbWindowLine <= 143) {
210
211 tile_map = 0x1800;
212
213 if((register_LCDC & 0x40) != 0)
214 tile_map = 0x1c00;
215
216 if(gbWindowLine == -1) {
217 gbWindowLine = 0;
218 }
219
220 tx = 0;
221 ty = gbWindowLine >> 3;
222
223 bx = 128;
224 by = gbWindowLine & 7;
225
226 if(wx < 0) {
227 bx >>= (-wx);
228 wx = 0;
229 }
230
231 tile_map_line_y = tile_map + ty * 32;
232
233 tile_map_address = tile_map_line_y + tx;
234
235 x = wx;
236
237 tile = bank0[tile_map_address];
238 u8 attrs = 0;
239 if(bank1)
240 attrs = bank1[tile_map_address];
241 tile_map_address++;
242
243 if((register_LCDC & 16) == 0) {
244 if(tile < 128) tile += 128;
245 else tile -= 128;
246 }
247
248 tile_pattern_address = tile_pattern + tile * 16 + by*2;
249
250 while(x < 160) {
251 u8 tile_a = 0;
252 u8 tile_b = 0;
253
254 if(attrs & 0x40) {
255 tile_pattern_address = tile_pattern + tile * 16 + (7-by)*2;
256 }
257
258 if(attrs & 0x08) {
259 tile_a = bank1[tile_pattern_address++];
260 tile_b = bank1[tile_pattern_address];
261 } else {
262 tile_a = bank0[tile_pattern_address++];
263 tile_b = bank0[tile_pattern_address];
264 }
265
266 if(attrs & 0x20) {
267 tile_a = gbInvertTab[tile_a];
268 tile_b = gbInvertTab[tile_b];
269 }
270
271 while(bx > 0) {
272 u8 c = (tile_a & bx) != 0 ? 1 : 0;
273 c += ((tile_b & bx) != 0 ? 2 : 0);
274
275 if(attrs & 0x80)
276 gbLineBuffer[x] = 0x300 + c;
277 else
278 gbLineBuffer[x] = 0x100 + c;
279
280 if(gbCgbMode) {
281 c = c + (attrs & 7) * 4;
282 } else {
283 c = gbBgp[c];
284 if(gbSgbMode && ! gbCgbMode) {
285 int dx = x >> 3;
286 int dy = y >> 3;
287
288 int palette = gbSgbATF[dy * 20 + dx];
289
290 if(c == 0)
291 palette = 0;
292
293 c = c + 4*palette;
294 }
295 }
296 gbLineMix[x] = gbColorOption ? gbColorFilter[gbPalette[c]] :
297 gbPalette[c];
298 x++;
299 if(x >= 160)
300 break;
301 bx >>= 1;
302 }
303 tx++;
304 if(tx == 32)
305 tx = 0;
306 bx = 128;
307 tile = bank0[tile_map_line_y + tx];
308 if(bank1)
309 attrs = bank1[tile_map_line_y + tx];
310
311 if((register_LCDC & 16) == 0) {
312 if(tile < 128) tile += 128;
313 else tile -= 128;
314 }
315 tile_pattern_address = tile_pattern + tile * 16 + by * 2;
316 }
317 gbWindowLine++;
318 }
319 }
320 }
321 } else {
322 for(int i = 0; i < 160; i++) {
323 gbLineMix[i] = gbPalette[0];
324 gbLineBuffer[i] = 0;
325 }
326 }
327 }
328
gbDrawSpriteTile(int tile,int x,int y,int t,int flags,int size,int spriteNumber)329 void gbDrawSpriteTile(int tile, int x,int y,int t, int flags,
330 int size,int spriteNumber)
331 {
332 u8 * bank0;
333 u8 * bank1;
334 if(gbCgbMode) {
335 if(register_VBK & 1) {
336 bank0 = &gbVram[0x0000];
337 bank1 = &gbVram[0x2000];
338 } else {
339 bank0 = &gbVram[0x0000];
340 bank1 = &gbVram[0x2000];
341 }
342 } else {
343 bank0 = &gbMemory[0x8000];
344 bank1 = NULL;
345 }
346
347 int init = 0x0000;
348
349 // int yLine = (y+gbBorderRowSkip) * gbBorderLineSkip;
350
351 u8 *pal = gbObp0;
352
353 int flipx = (flags & 0x20);
354 int flipy = (flags & 0x40);
355
356 if((flags & 0x10))
357 pal = gbObp1;
358
359 if(flipy) {
360 t = (size ? 15 : 7) - t;
361 }
362
363 int prio = flags & 0x80;
364
365 int address = init + tile * 16 + 2*t;
366 int a = 0;
367 int b = 0;
368
369 if(gbCgbMode && flags & 0x08) {
370 a = bank1[address++];
371 b = bank1[address++];
372 } else {
373 a = bank0[address++];
374 b = bank0[address++];
375 }
376
377 for(int xx = 0; xx < 8; xx++) {
378 u8 mask = 1 << (7-xx);
379 u8 c = 0;
380 if( (a & mask))
381 c++;
382 if( (b & mask))
383 c+=2;
384
385 if(c==0) continue;
386
387 int xxx = xx+x;
388 if(flipx)
389 xxx = (7-xx+x);
390
391 if(xxx < 0 || xxx > 159)
392 continue;
393
394 u16 color = gbLineBuffer[xxx];
395
396 if(prio) {
397 if(color < 0x200 && ((color & 0xFF) != 0))
398 continue;
399 }
400 if(color >= 0x300 && color != 0x300)
401 continue;
402 else if(color >= 0x200 && color < 0x300) {
403 int sprite = color & 0xff;
404
405 int spriteX = gbMemory[0xfe00 + 4 * sprite + 1] - 8;
406
407 if(spriteX == x) {
408 if(sprite < spriteNumber)
409 continue;
410 } else {
411 if(gbCgbMode) {
412 if(sprite < spriteNumber)
413 continue;
414 } else {
415 if(spriteX < x+8)
416 continue;
417 }
418 }
419 }
420
421
422 gbLineBuffer[xxx] = 0x200 + spriteNumber;
423
424 // make sure that sprites will work even in CGB mode
425 if(gbCgbMode) {
426 c = c + (flags & 0x07)*4 + 32;
427 } else {
428 c = pal[c];
429
430 if(gbSgbMode && !gbCgbMode) {
431 int dx = xxx >> 3;
432 int dy = y >> 3;
433
434 int palette = gbSgbATF[dy * 20 + dx];
435
436 if(c == 0)
437 palette = 0;
438
439 c = c + 4*palette;
440 } else {
441 c += 4;
442 }
443 }
444
445 gbLineMix[xxx] = gbColorOption ? gbColorFilter[gbPalette[c]] :
446 gbPalette[c];
447 }
448 }
449
gbDrawSprites()450 void gbDrawSprites()
451 {
452 int x = 0;
453 int y = 0;
454 int count = 0;
455
456 int size = (register_LCDC & 4);
457
458 if(!(register_LCDC & 0x80))
459 return;
460
461 if((register_LCDC & 2) && (layerSettings & 0x1000)) {
462 int yc = register_LY;
463
464 int address = 0xfe00;
465 for(int i = 0; i < 40; i++) {
466 y = gbMemory[address++];
467 x = gbMemory[address++];
468 int tile = gbMemory[address++];
469 if(size)
470 tile &= 254;
471 int flags = gbMemory[address++];
472
473 if(x > 0 && y > 0 && x < 168 && y < 160) {
474 // check if sprite intersects current line
475 int t = yc -y + 16;
476 if(size && t >=0 && t < 16) {
477 gbDrawSpriteTile(tile,x-8,yc,t,flags,size,i);
478 count++;
479 } else if(!size && t >= 0 && t < 8) {
480 gbDrawSpriteTile(tile, x-8, yc, t, flags,size,i);
481 count++;
482 }
483 }
484 // sprite limit reached!
485 if(count >= 10)
486 break;
487 }
488 }
489 }
490
491