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 #include "gfx-draw.h"
23 
24 namespace MDFN_IEN_GBA
25 {
26 
mode5RenderLine()27 void mode5RenderLine()
28 {
29   if(DISPCNT & 0x0080) {
30     for(int x = 0; x < 240; x++) {
31       lineMix[x] = 0x7fff;
32     }
33     gfxLastVCOUNT = VCOUNT;
34     return;
35   }
36 
37   uint16 *palette = (uint16 *)paletteRAM;
38 
39   if(layerEnable & 0x0400) {
40     int changed = gfxBG2Changed;
41 
42     if(gfxLastVCOUNT > VCOUNT)
43       changed = 3;
44 
45     gfxDrawRotScreen16Bit160(BG2CNT, BG2X_L, BG2X_H,
46                              BG2Y_L, BG2Y_H, BG2PA, BG2PB,
47                              BG2PC, BG2PD,
48                              gfxBG2X, gfxBG2Y, changed,
49                              line2);
50   }
51 
52   gfxDrawSprites();
53 
54   uint32 background = (READ16LE(&palette[0]) | 0x30000000);
55 
56   for(int x = 0; x < 240; x++) {
57     uint32 color = background;
58     uint8 top = 0x20;
59 
60     if(line2[x] < color) {
61       color = line2[x];
62       top = 0x04;
63     }
64 
65     if((uint8)(lineOBJ[x]>>24) < (uint8)(color >>24)) {
66       color = lineOBJ[x];
67       top = 0x10;
68     }
69 
70     if((top & 0x10) && (color & 0x00010000)) {
71       // semi-transparent OBJ
72       uint32 back = background;
73       uint8 top2 = 0x20;
74 
75       if(line2[x] < back) {
76         back = line2[x];
77         top2 = 0x04;
78       }
79 
80       if(top2 & (BLDMOD>>8))
81         color = gfxAlphaBlend(color, back,
82                               all_coeff[COLEV & 0x1F],
83                               all_coeff[(COLEV >> 8) & 0x1F]);
84       else {
85         switch((BLDMOD >> 6) & 3) {
86         case 2:
87           if(BLDMOD & top)
88             color = gfxIncreaseBrightness(color, all_coeff[COLY & 0x1F]);
89           break;
90         case 3:
91           if(BLDMOD & top)
92             color = gfxDecreaseBrightness(color, all_coeff[COLY & 0x1F]);
93           break;
94         }
95       }
96     }
97 
98     lineMix[x] = color;
99   }
100   gfxBG2Changed = 0;
101   gfxLastVCOUNT = VCOUNT;
102 }
103 
mode5RenderLineNoWindow()104 void mode5RenderLineNoWindow()
105 {
106   if(DISPCNT & 0x0080) {
107     for(int x = 0; x < 240; x++) {
108       lineMix[x] = 0x7fff;
109     }
110     gfxLastVCOUNT = VCOUNT;
111     return;
112   }
113 
114   uint16 *palette = (uint16 *)paletteRAM;
115 
116   if(layerEnable & 0x0400) {
117     int changed = gfxBG2Changed;
118 
119     if(gfxLastVCOUNT > VCOUNT)
120       changed = 3;
121 
122     gfxDrawRotScreen16Bit160(BG2CNT, BG2X_L, BG2X_H,
123                              BG2Y_L, BG2Y_H, BG2PA, BG2PB,
124                              BG2PC, BG2PD,
125                              gfxBG2X, gfxBG2Y, changed,
126                              line2);
127   }
128 
129   gfxDrawSprites();
130 
131   uint32 background = ( READ16LE(&palette[0]) | 0x30000000);
132 
133   for(int x = 0; x < 240; x++) {
134     uint32 color = background;
135     uint8 top = 0x20;
136 
137     if(line2[x] < color) {
138       color = line2[x];
139       top = 0x04;
140     }
141 
142     if((uint8)(lineOBJ[x]>>24) < (uint8)(color >>24)) {
143       color = lineOBJ[x];
144       top = 0x10;
145     }
146 
147     if(!(color & 0x00010000)) {
148       switch((BLDMOD >> 6) & 3) {
149       case 0:
150         break;
151       case 1:
152         {
153           if(top & BLDMOD) {
154             uint32 back = background;
155             uint8 top2 = 0x20;
156 
157             if(line2[x] < back) {
158               if(top != 0x04) {
159                 back = line2[x];
160                 top2 = 0x04;
161               }
162             }
163 
164             if((uint8)(lineOBJ[x]>>24) < (uint8)(back >> 24)) {
165               if(top != 0x10) {
166                 back = lineOBJ[x];
167                 top2 = 0x10;
168               }
169             }
170 
171             if(top2 & (BLDMOD>>8))
172               color = gfxAlphaBlend(color, back,
173                                     all_coeff[COLEV & 0x1F],
174                                     all_coeff[(COLEV >> 8) & 0x1F]);
175 
176           }
177         }
178         break;
179       case 2:
180         if(BLDMOD & top)
181           color = gfxIncreaseBrightness(color, all_coeff[COLY & 0x1F]);
182         break;
183       case 3:
184         if(BLDMOD & top)
185           color = gfxDecreaseBrightness(color, all_coeff[COLY & 0x1F]);
186         break;
187       }
188     } else {
189       // semi-transparent OBJ
190       uint32 back = background;
191       uint8 top2 = 0x20;
192 
193       if(line2[x] < back) {
194         back = line2[x];
195         top2 = 0x04;
196       }
197 
198       if(top2 & (BLDMOD>>8))
199         color = gfxAlphaBlend(color, back,
200                               all_coeff[COLEV & 0x1F],
201                               all_coeff[(COLEV >> 8) & 0x1F]);
202       else {
203         switch((BLDMOD >> 6) & 3) {
204         case 2:
205           if(BLDMOD & top)
206             color = gfxIncreaseBrightness(color, all_coeff[COLY & 0x1F]);
207           break;
208         case 3:
209           if(BLDMOD & top)
210             color = gfxDecreaseBrightness(color, all_coeff[COLY & 0x1F]);
211           break;
212         }
213       }
214     }
215 
216     lineMix[x] = color;
217   }
218   gfxBG2Changed = 0;
219   gfxLastVCOUNT = VCOUNT;
220 }
221 
mode5RenderLineAll()222 void mode5RenderLineAll()
223 {
224   if(DISPCNT & 0x0080) {
225     for(int x = 0; x < 240; x++) {
226       lineMix[x] = 0x7fff;
227     }
228     gfxLastVCOUNT = VCOUNT;
229     return;
230   }
231 
232   uint16 *palette = (uint16 *)paletteRAM;
233 
234   if(layerEnable & 0x0400) {
235     int changed = gfxBG2Changed;
236 
237     if(gfxLastVCOUNT > VCOUNT)
238       changed = 3;
239 
240     gfxDrawRotScreen16Bit160(BG2CNT, BG2X_L, BG2X_H,
241                              BG2Y_L, BG2Y_H, BG2PA, BG2PB,
242                              BG2PC, BG2PD,
243                              gfxBG2X, gfxBG2Y, changed,
244                              line2);
245   }
246 
247   gfxDrawSprites();
248   gfxDrawOBJWin();
249 
250   bool inWindow0 = false;
251   bool inWindow1 = false;
252 
253   if(layerEnable & 0x2000) {
254     uint8 v0 = WIN0V >> 8;
255     uint8 v1 = WIN0V & 255;
256     inWindow0 = ((v0 == v1) && (v0 >= 0xe8));
257     if(v1 >= v0)
258       inWindow0 |= (VCOUNT >= v0 && VCOUNT < v1);
259     else
260       inWindow0 |= (VCOUNT >= v0 || VCOUNT < v1);
261   }
262   if(layerEnable & 0x4000) {
263     uint8 v0 = WIN1V >> 8;
264     uint8 v1 = WIN1V & 255;
265     inWindow1 = ((v0 == v1) && (v0 >= 0xe8));
266     if(v1 >= v0)
267       inWindow1 |= (VCOUNT >= v0 && VCOUNT < v1);
268     else
269       inWindow1 |= (VCOUNT >= v0 || VCOUNT < v1);
270   }
271 
272   uint8 inWin0Mask = WININ & 0xFF;
273   uint8 inWin1Mask = WININ >> 8;
274   uint8 outMask = WINOUT & 0xFF;
275 
276   uint32 background = (READ16LE(&palette[0]) | 0x30000000);
277 
278   for(int x = 0; x < 240; x++) {
279     uint32 color = background;
280     uint8 top = 0x20;
281     uint8 mask = outMask;
282 
283     if(!(lineOBJWin[x] & 0x80000000)) {
284       mask = WINOUT >> 8;
285     }
286 
287     if(inWindow1) {
288       if(gfxInWin1[x])
289         mask = inWin1Mask;
290     }
291 
292     if(inWindow0) {
293       if(gfxInWin0[x]) {
294         mask = inWin0Mask;
295       }
296     }
297 
298     if((mask & 4) && (line2[x] < color)) {
299       color = line2[x];
300       top = 0x04;
301     }
302 
303     if((mask & 16) && ((uint8)(lineOBJ[x]>>24) < (uint8)(color >>24))) {
304       color = lineOBJ[x];
305       top = 0x10;
306     }
307 
308     if(mask & 32) {
309       if(!(color & 0x00010000)) {
310         switch((BLDMOD >> 6) & 3) {
311         case 0:
312           break;
313         case 1:
314           {
315             if(top & BLDMOD) {
316               uint32 back = background;
317               uint8 top2 = 0x20;
318 
319               if((mask & 4) && line2[x] < back) {
320                 if(top != 0x04) {
321                   back = line2[x];
322                   top2 = 0x04;
323                 }
324               }
325 
326               if((mask & 16) && (uint8)(lineOBJ[x]>>24) < (uint8)(back >> 24)) {
327                 if(top != 0x10) {
328                   back = lineOBJ[x];
329                   top2 = 0x10;
330                 }
331               }
332 
333               if(top2 & (BLDMOD>>8))
334                 color = gfxAlphaBlend(color, back,
335                                       all_coeff[COLEV & 0x1F],
336                                       all_coeff[(COLEV >> 8) & 0x1F]);
337 
338             }
339           }
340           break;
341         case 2:
342           if(BLDMOD & top)
343             color = gfxIncreaseBrightness(color, all_coeff[COLY & 0x1F]);
344           break;
345         case 3:
346           if(BLDMOD & top)
347             color = gfxDecreaseBrightness(color, all_coeff[COLY & 0x1F]);
348           break;
349         }
350       } else {
351         // semi-transparent OBJ
352         uint32 back = background;
353         uint8 top2 = 0x20;
354 
355         if((mask & 4) && line2[x] < back) {
356           back = line2[x];
357           top2 = 0x04;
358         }
359 
360         if(top2 & (BLDMOD>>8))
361           color = gfxAlphaBlend(color, back,
362                                 all_coeff[COLEV & 0x1F],
363                                 all_coeff[(COLEV >> 8) & 0x1F]);
364         else {
365           switch((BLDMOD >> 6) & 3) {
366           case 2:
367             if(BLDMOD & top)
368               color = gfxIncreaseBrightness(color, all_coeff[COLY & 0x1F]);
369             break;
370           case 3:
371             if(BLDMOD & top)
372               color = gfxDecreaseBrightness(color, all_coeff[COLY & 0x1F]);
373             break;
374           }
375         }
376       }
377     } else if(color & 0x00010000) {
378       // semi-transparent OBJ
379       uint32 back = background;
380       uint8 top2 = 0x20;
381 
382       if((mask & 4) && line2[x] < back) {
383         back = line2[x];
384         top2 = 0x04;
385       }
386 
387       if(top2 & (BLDMOD>>8))
388         color = gfxAlphaBlend(color, back,
389                               all_coeff[COLEV & 0x1F],
390                               all_coeff[(COLEV >> 8) & 0x1F]);
391       else {
392         switch((BLDMOD >> 6) & 3) {
393         case 2:
394           if(BLDMOD & top)
395             color = gfxIncreaseBrightness(color, all_coeff[COLY & 0x1F]);
396           break;
397         case 3:
398           if(BLDMOD & top)
399             color = gfxDecreaseBrightness(color, all_coeff[COLY & 0x1F]);
400           break;
401         }
402       }
403     }
404 
405     lineMix[x] = color;
406   }
407   gfxBG2Changed = 0;
408   gfxLastVCOUNT = VCOUNT;
409 }
410 
411 }
412