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