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 "GBA.h"
20 #include "Globals.h"
21 #include "Gfx.h"
22 
mode1RenderLine()23 void mode1RenderLine()
24 {
25   u16 *palette = (u16 *)paletteRAM;
26 
27   if(DISPCNT & 0x80) {
28     for(int x = 0; x < 240; x++) {
29       lineMix[x] = 0x7fff;
30     }
31     gfxLastVCOUNT = VCOUNT;
32     return;
33   }
34 
35   if(layerEnable & 0x0100) {
36     gfxDrawTextScreen(BG0CNT, BG0HOFS, BG0VOFS, line0);
37   }
38 
39   if(layerEnable & 0x0200) {
40     gfxDrawTextScreen(BG1CNT, BG1HOFS, BG1VOFS, line1);
41   }
42 
43   if(layerEnable & 0x0400) {
44     int changed = gfxBG2Changed;
45     if(gfxLastVCOUNT > VCOUNT)
46       changed = 3;
47     gfxDrawRotScreen(BG2CNT, BG2X_L, BG2X_H, BG2Y_L, BG2Y_H,
48                      BG2PA, BG2PB, BG2PC, BG2PD,
49                      gfxBG2X, gfxBG2Y, changed, line2);
50   }
51 
52   gfxDrawSprites(lineOBJ);
53 
54   u32 backdrop = (READ16LE(&palette[0]) | 0x30000000);
55 
56   for(int x = 0; x < 240; x++) {
57     u32 color = backdrop;
58     u8 top = 0x20;
59 
60     if(line0[x] < color) {
61       color = line0[x];
62       top = 0x01;
63     }
64 
65     if((u8)(line1[x]>>24) < (u8)(color >> 24)) {
66       color = line1[x];
67       top = 0x02;
68     }
69 
70     if((u8)(line2[x]>>24) < (u8)(color >> 24)) {
71       color = line2[x];
72       top = 0x04;
73     }
74 
75     if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) {
76       color = lineOBJ[x];
77       top = 0x10;
78     }
79 
80     if((top & 0x10) && (color & 0x00010000)) {
81       // semi-transparent OBJ
82       u32 back = backdrop;
83       u8 top2 = 0x20;
84 
85       if((u8)(line0[x]>>24) < (u8)(back >> 24)) {
86         back = line0[x];
87         top2 = 0x01;
88       }
89 
90       if((u8)(line1[x]>>24) < (u8)(back >> 24)) {
91         back = line1[x];
92         top2 = 0x02;
93       }
94 
95       if((u8)(line2[x]>>24) < (u8)(back >> 24)) {
96         back = line2[x];
97         top2 = 0x04;
98       }
99 
100       if(top2 & (BLDMOD>>8))
101         color = gfxAlphaBlend(color, back,
102                               coeff[COLEV & 0x1F],
103                               coeff[(COLEV >> 8) & 0x1F]);
104       else {
105         switch((BLDMOD >> 6) & 3) {
106         case 2:
107           if(BLDMOD & top)
108             color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
109           break;
110         case 3:
111           if(BLDMOD & top)
112             color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
113           break;
114         }
115       }
116     }
117 
118     lineMix[x] = color;
119   }
120   gfxBG2Changed = 0;
121   gfxLastVCOUNT = VCOUNT;
122 }
123 
mode1RenderLineNoWindow()124 void mode1RenderLineNoWindow()
125 {
126   u16 *palette = (u16 *)paletteRAM;
127 
128   if(DISPCNT & 0x80) {
129     for(int x = 0; x < 240; x++) {
130       lineMix[x] = 0x7fff;
131     }
132     gfxLastVCOUNT = VCOUNT;
133     return;
134   }
135 
136   if(layerEnable & 0x0100) {
137     gfxDrawTextScreen(BG0CNT, BG0HOFS, BG0VOFS, line0);
138   }
139 
140 
141   if(layerEnable & 0x0200) {
142     gfxDrawTextScreen(BG1CNT, BG1HOFS, BG1VOFS, line1);
143   }
144 
145   if(layerEnable & 0x0400) {
146     int changed = gfxBG2Changed;
147     if(gfxLastVCOUNT > VCOUNT)
148       changed = 3;
149     gfxDrawRotScreen(BG2CNT, BG2X_L, BG2X_H, BG2Y_L, BG2Y_H,
150                      BG2PA, BG2PB, BG2PC, BG2PD,
151                      gfxBG2X, gfxBG2Y, changed, line2);
152   }
153 
154   gfxDrawSprites(lineOBJ);
155 
156   u32 backdrop = (READ16LE(&palette[0]) | 0x30000000);
157 
158   for(int x = 0; x < 240; x++) {
159     u32 color = backdrop;
160     u8 top = 0x20;
161 
162     if(line0[x] < color) {
163       color = line0[x];
164       top = 0x01;
165     }
166 
167     if((u8)(line1[x]>>24) < (u8)(color >> 24)) {
168       color = line1[x];
169       top = 0x02;
170     }
171 
172     if((u8)(line2[x]>>24) < (u8)(color >> 24)) {
173       color = line2[x];
174       top = 0x04;
175     }
176 
177     if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24)) {
178       color = lineOBJ[x];
179       top = 0x10;
180     }
181 
182     if(!(color & 0x00010000)) {
183       switch((BLDMOD >> 6) & 3) {
184       case 0:
185         break;
186       case 1:
187         {
188           if(top & BLDMOD) {
189             u32 back = backdrop;
190             u8 top2 = 0x20;
191             if((u8)(line0[x]>>24) < (u8)(back >> 24)) {
192               if(top != 0x01) {
193                 back = line0[x];
194                 top2 = 0x01;
195               }
196             }
197 
198             if((u8)(line1[x]>>24) < (u8)(back >> 24)) {
199               if(top != 0x02) {
200                 back = line1[x];
201                 top2 = 0x02;
202               }
203             }
204 
205             if((u8)(line2[x]>>24) < (u8)(back >> 24)) {
206               if(top != 0x04) {
207                 back = line2[x];
208                 top2 = 0x04;
209               }
210             }
211 
212             if((u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
213               if(top != 0x10) {
214                 back = lineOBJ[x];
215                 top2 = 0x10;
216               }
217             }
218 
219             if(top2 & (BLDMOD>>8))
220               color = gfxAlphaBlend(color, back,
221                                     coeff[COLEV & 0x1F],
222                                     coeff[(COLEV >> 8) & 0x1F]);
223           }
224         }
225         break;
226       case 2:
227         if(BLDMOD & top)
228           color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
229         break;
230       case 3:
231         if(BLDMOD & top)
232           color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
233         break;
234       }
235     } else {
236       // semi-transparent OBJ
237       u32 back = backdrop;
238       u8 top2 = 0x20;
239 
240       if((u8)(line0[x]>>24) < (u8)(back >> 24)) {
241         back = line0[x];
242         top2 = 0x01;
243       }
244 
245       if((u8)(line1[x]>>24) < (u8)(back >> 24)) {
246         back = line1[x];
247         top2 = 0x02;
248       }
249 
250       if((u8)(line2[x]>>24) < (u8)(back >> 24)) {
251         back = line2[x];
252         top2 = 0x04;
253       }
254 
255       if(top2 & (BLDMOD>>8))
256         color = gfxAlphaBlend(color, back,
257                               coeff[COLEV & 0x1F],
258                               coeff[(COLEV >> 8) & 0x1F]);
259       else {
260         switch((BLDMOD >> 6) & 3) {
261         case 2:
262           if(BLDMOD & top)
263             color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
264           break;
265         case 3:
266           if(BLDMOD & top)
267             color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
268           break;
269         }
270       }
271     }
272 
273     lineMix[x] = color;
274   }
275   gfxBG2Changed = 0;
276   gfxLastVCOUNT = VCOUNT;
277 }
278 
mode1RenderLineAll()279 void mode1RenderLineAll()
280 {
281   u16 *palette = (u16 *)paletteRAM;
282 
283   if(DISPCNT & 0x80) {
284     for(int x = 0; x < 240; x++) {
285       lineMix[x] = 0x7fff;
286     }
287     gfxLastVCOUNT = VCOUNT;
288     return;
289   }
290 
291   bool inWindow0 = false;
292   bool inWindow1 = false;
293 
294   if(layerEnable & 0x2000) {
295     u8 v0 = WIN0V >> 8;
296     u8 v1 = WIN0V & 255;
297     inWindow0 = ((v0 == v1) && (v0 >= 0xe8));
298     if(v1 >= v0)
299       inWindow0 |= (VCOUNT >= v0 && VCOUNT < v1);
300     else
301       inWindow0 |= (VCOUNT >= v0 || VCOUNT < v1);
302   }
303   if(layerEnable & 0x4000) {
304     u8 v0 = WIN1V >> 8;
305     u8 v1 = WIN1V & 255;
306     inWindow1 = ((v0 == v1) && (v0 >= 0xe8));
307     if(v1 >= v0)
308       inWindow1 |= (VCOUNT >= v0 && VCOUNT < v1);
309     else
310       inWindow1 |= (VCOUNT >= v0 || VCOUNT < v1);
311   }
312 
313   if(layerEnable & 0x0100) {
314     gfxDrawTextScreen(BG0CNT, BG0HOFS, BG0VOFS, line0);
315   }
316 
317   if(layerEnable & 0x0200) {
318     gfxDrawTextScreen(BG1CNT, BG1HOFS, BG1VOFS, line1);
319   }
320 
321   if(layerEnable & 0x0400) {
322     int changed = gfxBG2Changed;
323     if(gfxLastVCOUNT > VCOUNT)
324       changed = 3;
325     gfxDrawRotScreen(BG2CNT, BG2X_L, BG2X_H, BG2Y_L, BG2Y_H,
326                      BG2PA, BG2PB, BG2PC, BG2PD,
327                      gfxBG2X, gfxBG2Y, changed, line2);
328   }
329 
330   gfxDrawSprites(lineOBJ);
331   gfxDrawOBJWin(lineOBJWin);
332 
333   u32 backdrop = (READ16LE(&palette[0]) | 0x30000000);
334 
335   u8 inWin0Mask = WININ & 0xFF;
336   u8 inWin1Mask = WININ >> 8;
337   u8 outMask = WINOUT & 0xFF;
338 
339   for(int x = 0; x < 240; x++) {
340     u32 color = backdrop;
341     u8 top = 0x20;
342     u8 mask = outMask;
343 
344     if(!(lineOBJWin[x] & 0x80000000)) {
345       mask = WINOUT >> 8;
346     }
347 
348     if(inWindow1) {
349       if(gfxInWin1[x])
350         mask = inWin1Mask;
351     }
352 
353     if(inWindow0) {
354       if(gfxInWin0[x]) {
355         mask = inWin0Mask;
356       }
357     }
358 
359     if(line0[x] < color && (mask & 1)) {
360       color = line0[x];
361       top = 0x01;
362     }
363 
364     if((u8)(line1[x]>>24) < (u8)(color >> 24) && (mask & 2)) {
365       color = line1[x];
366       top = 0x02;
367     }
368 
369     if((u8)(line2[x]>>24) < (u8)(color >> 24) && (mask & 4)) {
370       color = line2[x];
371       top = 0x04;
372     }
373 
374     if((u8)(lineOBJ[x]>>24) < (u8)(color >> 24) && (mask & 16)) {
375       color = lineOBJ[x];
376       top = 0x10;
377     }
378 
379     // special FX on the window
380     if(mask & 32) {
381       if(!(color & 0x00010000)) {
382         switch((BLDMOD >> 6) & 3) {
383         case 0:
384           break;
385         case 1:
386           {
387             if(top & BLDMOD) {
388               u32 back = backdrop;
389               u8 top2 = 0x20;
390               if((mask & 1) && (u8)(line0[x]>>24) < (u8)(back >> 24)) {
391                 if(top != 0x01) {
392                   back = line0[x];
393                   top2 = 0x01;
394                 }
395               }
396 
397               if((mask & 2) && (u8)(line1[x]>>24) < (u8)(back >> 24)) {
398                 if(top != 0x02) {
399                   back = line1[x];
400                   top2 = 0x02;
401                 }
402               }
403 
404               if((mask & 4) && (u8)(line2[x]>>24) < (u8)(back >> 24)) {
405                 if(top != 0x04) {
406                   back = line2[x];
407                   top2 = 0x04;
408                 }
409               }
410 
411               if((mask & 16) && (u8)(lineOBJ[x]>>24) < (u8)(back >> 24)) {
412                 if(top != 0x10) {
413                   back = lineOBJ[x];
414                   top2 = 0x10;
415                 }
416               }
417 
418               if(top2 & (BLDMOD>>8))
419                 color = gfxAlphaBlend(color, back,
420                                       coeff[COLEV & 0x1F],
421                                       coeff[(COLEV >> 8) & 0x1F]);
422             }
423           }
424           break;
425         case 2:
426           if(BLDMOD & top)
427             color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
428           break;
429         case 3:
430           if(BLDMOD & top)
431             color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
432           break;
433         }
434       } else {
435         // semi-transparent OBJ
436         u32 back = backdrop;
437         u8 top2 = 0x20;
438 
439         if((mask & 1) && (u8)(line0[x]>>24) < (u8)(back >> 24)) {
440           back = line0[x];
441           top2 = 0x01;
442         }
443 
444         if((mask & 2) && (u8)(line1[x]>>24) < (u8)(back >> 24)) {
445           back = line1[x];
446           top2 = 0x02;
447         }
448 
449         if((mask & 4) && (u8)(line2[x]>>24) < (u8)(back >> 24)) {
450           back = line2[x];
451           top2 = 0x04;
452         }
453 
454         if(top2 & (BLDMOD>>8))
455           color = gfxAlphaBlend(color, back,
456                                 coeff[COLEV & 0x1F],
457                                 coeff[(COLEV >> 8) & 0x1F]);
458         else {
459           switch((BLDMOD >> 6) & 3) {
460           case 2:
461             if(BLDMOD & top)
462               color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
463             break;
464           case 3:
465             if(BLDMOD & top)
466               color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
467             break;
468           }
469         }
470       }
471     } else if(color & 0x00010000) {
472       // semi-transparent OBJ
473       u32 back = backdrop;
474       u8 top2 = 0x20;
475 
476       if((mask & 1) && (u8)(line0[x]>>24) < (u8)(back >> 24)) {
477         back = line0[x];
478         top2 = 0x01;
479       }
480 
481       if((mask & 2) && (u8)(line1[x]>>24) < (u8)(back >> 24)) {
482         back = line1[x];
483         top2 = 0x02;
484       }
485 
486       if((mask & 4) && (u8)(line2[x]>>24) < (u8)(back >> 24)) {
487         back = line2[x];
488         top2 = 0x04;
489       }
490 
491       if(top2 & (BLDMOD>>8))
492         color = gfxAlphaBlend(color, back,
493                               coeff[COLEV & 0x1F],
494                               coeff[(COLEV >> 8) & 0x1F]);
495       else {
496         switch((BLDMOD >> 6) & 3) {
497         case 2:
498           if(BLDMOD & top)
499             color = gfxIncreaseBrightness(color, coeff[COLY & 0x1F]);
500           break;
501         case 3:
502           if(BLDMOD & top)
503             color = gfxDecreaseBrightness(color, coeff[COLY & 0x1F]);
504           break;
505         }
506       }
507     }
508 
509     lineMix[x] = color;
510   }
511   gfxBG2Changed = 0;
512   gfxLastVCOUNT = VCOUNT;
513 }
514