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