Previous 15994 Revisions Next

r7645 Friday 26th March, 2010 at 15:49:56 UTC by Fabio Priuli
re-applied rev 7636
[src/mame/video]snes.c

src/mame/video/snes.c
r7644r7645
132132   SNES_COLOR_DEPTH_8BPP
133133};
134134
135/*****************************************
136 * snes_draw_blend()
137 *
138 * Routine for additive/subtractive blending
139 * between the main and sub screens.
140 *****************************************/
135/**********************************************************************************
136 * TODO: the draw_tile routines below should be merged/reworked to reduce everything
137 * to a single routine with the additional parameters: OAM/BG (to decide if checking
138 * against priority or not) and tile length (16 for hires BG, 8 otherwise)
139 **********************************************************************************/
141140
142INLINE void snes_draw_blend( UINT16 offset, UINT16 *colour, UINT8 prevent_color_math, UINT8 black_pen_clip, int switch_screens )
143{
144#ifdef SNES_LAYER_DEBUG
145   if (debug_options.colormath_disabled)
146      return;
147#endif /* SNES_LAYER_DEBUG */
148
149   /* when color math is applied to subscreen pixels, the blending depends on the blending used by the previous mainscreen
150    pixel, except for subscreen pixel 0 which has no previous mainscreen pixel, see comments in snes_refresh_scanline */
151   if (switch_screens && offset > 0)
152      offset -= 1;
153
154   if ((black_pen_clip == SNES_CLIP_ALWAYS) ||
155      (black_pen_clip == SNES_CLIP_IN && snes_ppu.clipmasks[SNES_COLOR][offset]) ||
156      (black_pen_clip == SNES_CLIP_OUT && !snes_ppu.clipmasks[SNES_COLOR][offset]))
157      *colour = 0; //clip to black before color math
158
159   if (prevent_color_math == SNES_CLIP_ALWAYS) // blending mode 3 == always OFF
160      return;
161
162   if ((prevent_color_math == SNES_CLIP_NEVER) ||
163      (prevent_color_math == SNES_CLIP_IN  && !snes_ppu.clipmasks[SNES_COLOR][offset]) ||
164      (prevent_color_math == SNES_CLIP_OUT && snes_ppu.clipmasks[SNES_COLOR][offset]))
165   {
166      UINT16 r, g, b;
167      struct SCANLINE *subscreen;
168      int clip_max = 0;   // if add then clip to 0x1f, if sub then clip to 0
169
170#ifdef SNES_LAYER_DEBUG
171      /* Toggle drawing of SNES_SUBSCREEN or SNES_MAINSCREEN */
172      if (debug_options.draw_subscreen)
173      {
174         subscreen = switch_screens ? &scanlines[SNES_SUBSCREEN] : &scanlines[SNES_MAINSCREEN];
175      }
176      else
177#endif /* SNES_LAYER_DEBUG */
178      {
179         subscreen = switch_screens ? &scanlines[SNES_MAINSCREEN] : &scanlines[SNES_SUBSCREEN];
180      }
181
182      if (snes_ppu.sub_add_mode) /* SNES_SUBSCREEN*/
183      {
184         if (!BIT(snes_ppu.color_modes, 7))
185         {
186            /* 0x00 add */
187            r = (*colour & 0x1f) + (subscreen->buffer[offset] & 0x1f);
188            g = ((*colour & 0x3e0) >> 5) + ((subscreen->buffer[offset] & 0x3e0) >> 5);
189            b = ((*colour & 0x7c00) >> 10) + ((subscreen->buffer[offset] & 0x7c00) >> 10);
190            clip_max = 1;
191         }
192         else
193         {
194            /* 0x80 sub */
195            r = (*colour & 0x1f) - (subscreen->buffer[offset] & 0x1f);
196            g = ((*colour & 0x3e0) >> 5) - ((subscreen->buffer[offset] & 0x3e0) >> 5);
197            b = ((*colour & 0x7c00) >> 10) - ((subscreen->buffer[offset] & 0x7c00) >> 10);
198            if (r > 0x1f) r = 0;
199            if (g > 0x1f) g = 0;
200            if (b > 0x1f) b = 0;
201         }
202         /* only halve if the color is not the back colour */
203         if (BIT(snes_ppu.color_modes, 6) && (subscreen->buffer[offset] != snes_cgram[FIXED_COLOUR]))
204         {
205            r >>= 1;
206            g >>= 1;
207            b >>= 1;
208         }
209      }
210      else /* Fixed colour */
211      {
212         if (!BIT(snes_ppu.color_modes, 7))
213         {
214            /* 0x00 add */
215            r = (*colour & 0x1f) + (snes_cgram[FIXED_COLOUR] & 0x1f);
216            g = ((*colour & 0x3e0) >> 5) + ((snes_cgram[FIXED_COLOUR] & 0x3e0) >> 5);
217            b = ((*colour & 0x7c00) >> 10) + ((snes_cgram[FIXED_COLOUR] & 0x7c00) >> 10);
218            clip_max = 1;
219         }
220         else
221         {
222            /* 0x80: sub */
223            r = (*colour & 0x1f) - (snes_cgram[FIXED_COLOUR] & 0x1f);
224            g = ((*colour & 0x3e0) >> 5) - ((snes_cgram[FIXED_COLOUR] & 0x3e0) >> 5);
225            b = ((*colour & 0x7c00) >> 10) - ((snes_cgram[FIXED_COLOUR] & 0x7c00) >> 10);
226            if (r > 0x1f) r = 0;
227            if (g > 0x1f) g = 0;
228            if (b > 0x1f) b = 0;
229         }
230         /* halve if necessary */
231         if (BIT(snes_ppu.color_modes, 6))
232         {
233            r >>= 1;
234            g >>= 1;
235            b >>= 1;
236         }
237      }
238
239      /* according to anomie's docs, after addition has been performed, division by 2 happens *before* clipping to max, hence we clip now */
240      if (clip_max)
241      {
242         if (r > 0x1f) r = 0x1f;
243         if (g > 0x1f) g = 0x1f;
244         if (b > 0x1f) b = 0x1f;
245      }
246
247      *colour = ((r & 0x1f) | ((g & 0x1f) << 5) | ((b & 0x1f) << 10));
248   }
249}
250
251141/*****************************************
252142 * snes_draw_tile()
253143 *
254 * Draw tiles with variable bit planes
144 * Draw BG tiles with variable bit planes
255145 *****************************************/
256146
257147INLINE void snes_draw_tile( UINT8 planes, UINT8 layer, UINT16 tileaddr, INT16 x, UINT8 priority, UINT8 flip, UINT8 direct_colors, UINT16 pal, UINT8 hires )
r7644r7645
546436/*****************************************
547437 * snes_draw_tile_object()
548438 *
549 * Draw tiles with 4 bit planes(16 colors)
550 * The same as snes_draw_tile_4() except
551 * that it takes a blend parameter.
439 * Draw OAM tiles with 4 bit planes(16 colors)
552440 *****************************************/
553441
554442INLINE void snes_draw_tile_object( UINT16 tileaddr, INT16 x, UINT8 priority, UINT8 flip, UINT16 pal )
r7644r7645
648536   }
649537}
650538
539/*************************************************************************************************
540 * SNES BG layers
541 *
542 * BG drawing theory of each scanline is quite easy: depending on the graphics Mode (0-7), there
543 * are up to 4 background layers. Pixels for each BG layer can have two different priorities.
544 * Depending on the line and on the BGHOFS and BGVOFS PPU registers, we first determine the tile
545 * address in snes_vram (by determining x,y coord and tile size and by calling snes_get_tmap_addr).
546 * Then, we load the correspondent data and we determine the tile properties: which priority to
547 * use, which palette etc. Finally, for each pixel of the tile appearing on screen, we check if
548 * the tile priority is higher than the BG/OAM already stored in that pixel for that line. If so
549 * we store the pixel in the buffer, otherwise we discard it.
550 *
551 * Of course, depending on the graphics Mode, it might be easier or harder to determine the proper
552 * tile address in vram (Mode 7 uses different registers, Mode 2, 4 and 6 uses OPT effect, etc.),
553 * but in general it works as described.
554 *************************************************************************************************/
555
651556/*********************************************
652557 * snes_get_tmap_addr()
653558 *
r7644r7645
1071976   }
1072977}
1073978
1074/*********************************************
1075 * snes_update_objects()
979/*************************************************************************************************
980 * SNES Sprites
1076981 *
1077 * Update an entire line of sprites.
1078 * FIXME: We need to support high priority bit
1079 *********************************************/
982 * 1. First of all: sprites are drawn one line in advance. We emulate this by caching the
983 * starting vram address, the sprite size and the "name select" at each line, and by using
984 * them the next line to output the proper sprites - see snes_update_obsel.
985 *
986 * 2. Each line can select its sprites among 128 available ones in oam_ram, hence we start
987 * by creating a list of the available objects (each one with its x,y coordinate, its size,
988 * its tile address, etc.) - see snes_oam_list_build.
989 *
990 * 3. Next, we start finding out which sprites will appear in the line: starting from
991 * FirstSprite, we count 32 OBJs which intersect our line and we store their indexes in the
992 * oam_itemlist array (if more than 32 sprites intersect our line, we set the Range Over
993 * flag); then, selecting among these sprites, we count 34 8x8 tiles which are visible
994 * in our line (i.e. whose x coord is between -size and 256) and we store the corresponding
995 * coordinates/priorities/palettes/etc. in the oam_tilelist array (if more than 34 tiles would
996 * appear on screen, we set the Time Over flag).
997 * Notice that when we populate oam_tilelist, we proceed from oam_itemlist[31] (or from the last
998 * item which intersects the scanline), towards oam_itemlist[0], i.e. the higher tiles (say
999 * oam_tilelist[34], or the last tile which appear on screen) will contain FirstSprite object,
1000 * or the sprites with closer index to FirstSprite which get displayed. This will play an
1001 * important role for sprite priority - see snes_update_objects_rto.
1002 *
1003 * 4. All the above happens at the beginning of each VIDEO_UPDATE. When we finally draw the
1004 * scanline, we pass through the oam_tilelist and we store the displayed pixels in our scanline
1005 * buffer. Notice that, for each pixel of a SNES sprite, only the priority of the topmost sprite
1006 * is tested against the priority of the BG pixel (because FirstSprite is on top of FirstSprite+1,
1007 * which is on top of FirstSprite+2, etc., and therefore other sprites are already covered by the
1008 * topmost one). To emulate this, we draw each tile over the previous ones no matter what
1009 * priorities are (differently from what we did with BGs): in the end, we will have in each pixel z
1010 * its topmost sprite and scanline.priority[z] will be the topmost sprite priority as expected.
1011 * Of course, sprite drawing must happen before BG drawing, so that afterwords BG pixels properly
1012 * test their priority with the one of the correct sprite - see snes_update_objects.
1013 *************************************************************************************************/
10801014
10811015struct OAM
10821016{
r7644r7645
10881022
10891023static struct OAM oam_spritelist[SNES_SCR_WIDTH / 2];
10901024
1025static UINT8 oam_itemlist[32];
1026
1027struct TILELIST {
1028   INT16 x;
1029   UINT16 priority, pal, tileaddr;
1030   int hflip;
1031};
1032
1033struct TILELIST oam_tilelist[34];
1034
1035/*********************************************
1036 * snes_update_obsel()
1037 *
1038 * Update sprite settings for next line.
1039 *********************************************/
1040
10911041static void snes_update_obsel( void )
10921042{
10931043   snes_ppu.layer[SNES_OAM].charmap = snes_ppu.oam.next_charmap;
r7644r7645
11001050   }
11011051}
11021052
1053/*********************************************
1054 * snes_oam_list_build()
1055 *
1056 * Build a list of the available obj in OAM ram.
1057 *********************************************/
1058
11031059static void snes_oam_list_build( void )
11041060{
11051061   UINT8 *oamram = (UINT8 *)snes_oam;
11061062   INT16 oam = 0x1ff;
11071063   UINT16 oam_extra = oam + 0x20;
11081064   UINT16 extra = 0;
1109   int i;
1065   int ii;
11101066
11111067   snes_ppu.update_oam_list = 0;      // eventually, we can optimize the code by only calling this function when there is a change in size
11121068
1113   for (i = 127; i >= 0; i--)
1069   for (ii = 127; ii >= 0; ii--)
11141070   {
1115      if (((i + 1) % 4) == 0)
1071      if (((ii + 1) % 4) == 0)
11161072         extra = oamram[oam_extra--];
11171073
1118      oam_spritelist[i].vflip = (oamram[oam] & 0x80) >> 7;
1119      oam_spritelist[i].hflip = (oamram[oam] & 0x40) >> 6;
1120      oam_spritelist[i].priority_bits = (oamram[oam] & 0x30) >> 4;
1121      oam_spritelist[i].pal = 128 + ((oamram[oam] & 0x0e) << 3);
1122      oam_spritelist[i].tile = (oamram[oam--] & 0x1) << 8;
1123      oam_spritelist[i].tile |= oamram[oam--];
1124      oam_spritelist[i].y = oamram[oam--] + 1;   /* We seem to need to add one here.... */
1125      oam_spritelist[i].x = oamram[oam--];
1126      oam_spritelist[i].size = (extra & 0x80) >> 7;
1074      oam_spritelist[ii].vflip = (oamram[oam] & 0x80) >> 7;
1075      oam_spritelist[ii].hflip = (oamram[oam] & 0x40) >> 6;
1076      oam_spritelist[ii].priority_bits = (oamram[oam] & 0x30) >> 4;
1077      oam_spritelist[ii].pal = 128 + ((oamram[oam] & 0x0e) << 3);
1078      oam_spritelist[ii].tile = (oamram[oam--] & 0x1) << 8;
1079      oam_spritelist[ii].tile |= oamram[oam--];
1080      oam_spritelist[ii].y = oamram[oam--] + 1;   /* We seem to need to add one here.... */
1081      oam_spritelist[ii].x = oamram[oam--];
1082      oam_spritelist[ii].size = (extra & 0x80) >> 7;
11271083      extra <<= 1;
1128      oam_spritelist[i].x |= ((extra & 0x80) << 1);
1084      oam_spritelist[ii].x |= ((extra & 0x80) << 1);
11291085      extra <<= 1;
11301086
1131      oam_spritelist[i].y *= snes_ppu.obj_interlace;
1087      oam_spritelist[ii].y *= snes_ppu.obj_interlace;
11321088
11331089      /* Adjust if past maximum position */
1134      if (oam_spritelist[i].y >= snes_ppu.beam.last_visible_line * snes_ppu.interlace)
1135         oam_spritelist[i].y -= 256 * snes_ppu.interlace;
1090      if (oam_spritelist[ii].y >= snes_ppu.beam.last_visible_line * snes_ppu.interlace)
1091         oam_spritelist[ii].y -= 256 * snes_ppu.interlace;
11361092
1137      oam_spritelist[i].x &= 0x1ff;
1093      oam_spritelist[ii].x &= 0x1ff;
11381094
11391095      /* Determine object size */
11401096      switch (snes_ppu.oam.size)
11411097      {
11421098      case 0:         /* 8x8 or 16x16 */
1143         oam_spritelist[i].width  = oam_spritelist[i].size ? 2 : 1;
1144         oam_spritelist[i].height = oam_spritelist[i].size ? 2 : 1;
1099         oam_spritelist[ii].width  = oam_spritelist[ii].size ? 2 : 1;
1100         oam_spritelist[ii].height = oam_spritelist[ii].size ? 2 : 1;
11451101         break;
11461102      case 1:         /* 8x8 or 32x32 */
1147         oam_spritelist[i].width  = oam_spritelist[i].size ? 4 : 1;
1148         oam_spritelist[i].height = oam_spritelist[i].size ? 4 : 1;
1103         oam_spritelist[ii].width  = oam_spritelist[ii].size ? 4 : 1;
1104         oam_spritelist[ii].height = oam_spritelist[ii].size ? 4 : 1;
11491105         break;
11501106      case 2:         /* 8x8 or 64x64 */
1151         oam_spritelist[i].width  = oam_spritelist[i].size ? 8 : 1;
1152         oam_spritelist[i].height = oam_spritelist[i].size ? 8 : 1;
1107         oam_spritelist[ii].width  = oam_spritelist[ii].size ? 8 : 1;
1108         oam_spritelist[ii].height = oam_spritelist[ii].size ? 8 : 1;
11531109         break;
11541110      case 3:         /* 16x16 or 32x32 */
1155         oam_spritelist[i].width  = oam_spritelist[i].size ? 4 : 2;
1156         oam_spritelist[i].height = oam_spritelist[i].size ? 4 : 2;
1111         oam_spritelist[ii].width  = oam_spritelist[ii].size ? 4 : 2;
1112         oam_spritelist[ii].height = oam_spritelist[ii].size ? 4 : 2;
11571113         break;
11581114      case 4:         /* 16x16 or 64x64 */
1159         oam_spritelist[i].width  = oam_spritelist[i].size ? 8 : 2;
1160         oam_spritelist[i].height = oam_spritelist[i].size ? 8 : 2;
1115         oam_spritelist[ii].width  = oam_spritelist[ii].size ? 8 : 2;
1116         oam_spritelist[ii].height = oam_spritelist[ii].size ? 8 : 2;
11611117         break;
11621118      case 5:         /* 32x32 or 64x64 */
1163         oam_spritelist[i].width  = oam_spritelist[i].size ? 8 : 4;
1164         oam_spritelist[i].height = oam_spritelist[i].size ? 8 : 4;
1119         oam_spritelist[ii].width  = oam_spritelist[ii].size ? 8 : 4;
1120         oam_spritelist[ii].height = oam_spritelist[ii].size ? 8 : 4;
11651121         break;
11661122      case 6:         /* undocumented: 16x32 or 32x64 */
1167         oam_spritelist[i].width  = oam_spritelist[i].size ? 4 : 2;
1168         oam_spritelist[i].height = oam_spritelist[i].size ? 8 : 4;
1169         if (snes_ppu.obj_interlace && !oam_spritelist[i].size)
1170            oam_spritelist[i].height = 2;
1123         oam_spritelist[ii].width  = oam_spritelist[ii].size ? 4 : 2;
1124         oam_spritelist[ii].height = oam_spritelist[ii].size ? 8 : 4;
1125         if (snes_ppu.obj_interlace && !oam_spritelist[ii].size)
1126            oam_spritelist[ii].height = 2;
11711127         break;
11721128      case 7:         /* undocumented: 16x32 or 32x32 */
1173         oam_spritelist[i].width  = oam_spritelist[i].size ? 4 : 2;
1174         oam_spritelist[i].height = oam_spritelist[i].size ? 4 : 4;
1175         if (snes_ppu.obj_interlace && !oam_spritelist[i].size)
1176            oam_spritelist[i].height = 2;
1129         oam_spritelist[ii].width  = oam_spritelist[ii].size ? 4 : 2;
1130         oam_spritelist[ii].height = oam_spritelist[ii].size ? 4 : 4;
1131         if (snes_ppu.obj_interlace && !oam_spritelist[ii].size)
1132            oam_spritelist[ii].height = 2;
11771133         break;
11781134      default:
11791135         /* we should never enter here... */
r7644r7645
11831139   }
11841140}
11851141
1186static UINT8 oam_itemlist[32];
1142/*********************************************
1143 * is_sprite_on_scanline()
1144 *
1145 * Check if a given sprites intersect current
1146 * scanline
1147 *********************************************/
11871148
1188struct TILELIST {
1189   INT16 x;
1190   UINT16 priority, pal, tileaddr;
1191   int hflip;
1192};
1193
1194struct TILELIST oam_tilelist[34];
1195
11961149static int is_sprite_on_scanline( UINT16 curline, UINT8 sprite )
11971150{
11981151   //if sprite is entirely offscreen and doesn't wrap around to the left side of the screen,
r7644r7645
12111164   return 0;
12121165}
12131166
1167/*********************************************
1168 * snes_update_objects_rto()
1169 *
1170 * Determine which OBJs will be drawn on this
1171 * scanline.
1172 *********************************************/
1173
12141174static void snes_update_objects_rto( UINT16 curline )
12151175{
1216   int active_sprite;
1176   int ii, jj, active_sprite;
12171177   UINT8 range_over, time_over;
12181178   INT8 xs, ys;
12191179   UINT8 line;
12201180   UINT8 height, width, vflip, hflip, priority, pal;
12211181   UINT16 tile;
1222   INT16 i, x, y;
1182   INT16 x, y;
12231183   UINT32 name_sel = 0;
12241184
12251185   snes_oam_list_build();
r7644r7645
12361196   memset(oam_itemlist, 0xff, 32);
12371197
12381198   /* populate the list of 32 objects */
1239   for (i = 0; i < 128; i++)
1199   for (ii = 0; ii < 128; ii++)
12401200   {
1241      active_sprite = (i + snes_ppu.oam.first_sprite) & 0x7f;
1201      active_sprite = (ii + snes_ppu.oam.first_sprite) & 0x7f;
12421202
12431203      if (!is_sprite_on_scanline(curline, active_sprite))
12441204         continue;
r7644r7645
12501210   }
12511211
12521212   /* reset the list of first 34 tiles to be drawn */
1253   for (i = 0; i < 34; i++)
1254      oam_tilelist[i].tileaddr = 0xffff;
1213   for (ii = 0; ii < 34; ii++)
1214      oam_tilelist[ii].tileaddr = 0xffff;
12551215
12561216   /* populate the list of 34 tiles */
1257   for (i = 31; i >= 0; i--)
1217   for (ii = 31; ii >= 0; ii--)
12581218   {
1259      if (oam_itemlist[i] == 0xff)
1219      if (oam_itemlist[ii] == 0xff)
12601220         continue;
12611221
1262      active_sprite = oam_itemlist[i];
1222      active_sprite = oam_itemlist[ii];
12631223
12641224      tile = oam_spritelist[active_sprite].tile;
12651225      x = oam_spritelist[active_sprite].x;
r7644r7645
12841244      line <<= 1;
12851245      tile <<= 5;
12861246
1287      int ii;
1288
1289      for (ii = 0; ii < width; ii++)
1247      for (jj = 0; jj < width; jj++)
12901248      {
1291         INT16 xx = (x + (ii << 3)) & 0x1ff;
1249         INT16 xx = (x + (jj << 3)) & 0x1ff;
12921250
12931251         if (x != 256 && xx >= 256 && (xx + 7) < 512)
12941252            continue;
r7644r7645
12961254         if (time_over++ >= 34)
12971255            break;
12981256
1299         xs = (hflip) ? (width - 1 - ii) : ii;
1257         xs = (hflip) ? (width - 1 - jj) : jj;
13001258         oam_tilelist[time_over - 1].tileaddr = name_sel + tile + table_obj_offset[ys][xs] + line;
13011259         oam_tilelist[time_over - 1].hflip = hflip;
13021260         oam_tilelist[time_over - 1].x = xx;
r7644r7645
13141272      snes_ppu.stat77_flags |= 0x80;
13151273}
13161274
1275/*********************************************
1276 * snes_update_objects()
1277 *
1278 * Update an entire line of sprites.
1279 *********************************************/
1280
13171281static void snes_update_objects( UINT8 priority_oam0, UINT8 priority_oam1, UINT8 priority_oam2, UINT8 priority_oam3 )
13181282{
13191283   UINT8 pri, priority[4];
13201284   UINT32 charaddr;
1321   int i;
1285   int ii;
13221286
13231287#ifdef SNES_LAYER_DEBUG
13241288   if (debug_options.bg_disabled[SNES_OAM])
r7644r7645
13411305   priority[3] = priority_oam3;
13421306
13431307   /* finally draw the tiles from the tilelist */
1344   for (i = 0; i < 34; i++)
1308   for (ii = 0; ii < 34; ii++)
13451309   {
1346      int tile = i;
1310      int tile = ii;
13471311#ifdef SNES_LAYER_DEBUG
13481312      if (debug_options.sprite_reversed)
1349         tile = 33 - i;
1313         tile = 33 - ii;
13501314#endif /* SNES_LAYER_DEBUG */
13511315
13521316      if (oam_tilelist[tile].tileaddr == 0xffff)
r7644r7645
15941558 * snes_update_offsets()
15951559 *
15961560 * Update the offsets with the latest changes.
1561 * This is currently unused, but it could
1562 * possibly be handy for some minor optimization
15971563 *********************************************/
15981564
15991565static void snes_update_offsets( void )
r7644r7645
16051571   snes_ppu.update_offsets = 0;
16061572}
16071573
1574/*****************************************
1575 * snes_draw_blend()
1576 *
1577 * Routine for additive/subtractive blending
1578 * between the main and sub screens, i.e.
1579 * color math.
1580 *****************************************/
1581
1582INLINE void snes_draw_blend( UINT16 offset, UINT16 *colour, UINT8 prevent_color_math, UINT8 black_pen_clip, int switch_screens )
1583{
1584#ifdef SNES_LAYER_DEBUG
1585   if (debug_options.colormath_disabled)
1586      return;
1587#endif /* SNES_LAYER_DEBUG */
1588
1589   /* when color math is applied to subscreen pixels, the blending depends on the blending used by the previous mainscreen
1590    pixel, except for subscreen pixel 0 which has no previous mainscreen pixel, see comments in snes_refresh_scanline */
1591   if (switch_screens && offset > 0)
1592      offset -= 1;
1593
1594   if ((black_pen_clip == SNES_CLIP_ALWAYS) ||
1595      (black_pen_clip == SNES_CLIP_IN && snes_ppu.clipmasks[SNES_COLOR][offset]) ||
1596      (black_pen_clip == SNES_CLIP_OUT && !snes_ppu.clipmasks[SNES_COLOR][offset]))
1597      *colour = 0; //clip to black before color math
1598
1599   if (prevent_color_math == SNES_CLIP_ALWAYS) // blending mode 3 == always OFF
1600      return;
1601
1602   if ((prevent_color_math == SNES_CLIP_NEVER) ||
1603      (prevent_color_math == SNES_CLIP_IN  && !snes_ppu.clipmasks[SNES_COLOR][offset]) ||
1604      (prevent_color_math == SNES_CLIP_OUT && snes_ppu.clipmasks[SNES_COLOR][offset]))
1605   {
1606      UINT16 r, g, b;
1607      struct SCANLINE *subscreen;
1608      int clip_max = 0;   // if add then clip to 0x1f, if sub then clip to 0
1609
1610#ifdef SNES_LAYER_DEBUG
1611      /* Toggle drawing of SNES_SUBSCREEN or SNES_MAINSCREEN */
1612      if (debug_options.draw_subscreen)
1613      {
1614         subscreen = switch_screens ? &scanlines[SNES_SUBSCREEN] : &scanlines[SNES_MAINSCREEN];
1615      }
1616      else
1617#endif /* SNES_LAYER_DEBUG */
1618      {
1619         subscreen = switch_screens ? &scanlines[SNES_MAINSCREEN] : &scanlines[SNES_SUBSCREEN];
1620      }
1621
1622      if (snes_ppu.sub_add_mode) /* SNES_SUBSCREEN*/
1623      {
1624         if (!BIT(snes_ppu.color_modes, 7))
1625         {
1626            /* 0x00 add */
1627            r = (*colour & 0x1f) + (subscreen->buffer[offset] & 0x1f);
1628            g = ((*colour & 0x3e0) >> 5) + ((subscreen->buffer[offset] & 0x3e0) >> 5);
1629            b = ((*colour & 0x7c00) >> 10) + ((subscreen->buffer[offset] & 0x7c00) >> 10);
1630            clip_max = 1;
1631         }
1632         else
1633         {
1634            /* 0x80 sub */
1635            r = (*colour & 0x1f) - (subscreen->buffer[offset] & 0x1f);
1636            g = ((*colour & 0x3e0) >> 5) - ((subscreen->buffer[offset] & 0x3e0) >> 5);
1637            b = ((*colour & 0x7c00) >> 10) - ((subscreen->buffer[offset] & 0x7c00) >> 10);
1638            if (r > 0x1f) r = 0;
1639            if (g > 0x1f) g = 0;
1640            if (b > 0x1f) b = 0;
1641         }
1642         /* only halve if the color is not the back colour */
1643         if (BIT(snes_ppu.color_modes, 6) && (subscreen->buffer[offset] != snes_cgram[FIXED_COLOUR]))
1644         {
1645            r >>= 1;
1646            g >>= 1;
1647            b >>= 1;
1648         }
1649      }
1650      else /* Fixed colour */
1651      {
1652         if (!BIT(snes_ppu.color_modes, 7))
1653         {
1654            /* 0x00 add */
1655            r = (*colour & 0x1f) + (snes_cgram[FIXED_COLOUR] & 0x1f);
1656            g = ((*colour & 0x3e0) >> 5) + ((snes_cgram[FIXED_COLOUR] & 0x3e0) >> 5);
1657            b = ((*colour & 0x7c00) >> 10) + ((snes_cgram[FIXED_COLOUR] & 0x7c00) >> 10);
1658            clip_max = 1;
1659         }
1660         else
1661         {
1662            /* 0x80: sub */
1663            r = (*colour & 0x1f) - (snes_cgram[FIXED_COLOUR] & 0x1f);
1664            g = ((*colour & 0x3e0) >> 5) - ((snes_cgram[FIXED_COLOUR] & 0x3e0) >> 5);
1665            b = ((*colour & 0x7c00) >> 10) - ((snes_cgram[FIXED_COLOUR] & 0x7c00) >> 10);
1666            if (r > 0x1f) r = 0;
1667            if (g > 0x1f) g = 0;
1668            if (b > 0x1f) b = 0;
1669         }
1670         /* halve if necessary */
1671         if (BIT(snes_ppu.color_modes, 6))
1672         {
1673            r >>= 1;
1674            g >>= 1;
1675            b >>= 1;
1676         }
1677      }
1678
1679      /* according to anomie's docs, after addition has been performed, division by 2 happens *before* clipping to max, hence we clip now */
1680      if (clip_max)
1681      {
1682         if (r > 0x1f) r = 0x1f;
1683         if (g > 0x1f) g = 0x1f;
1684         if (b > 0x1f) b = 0x1f;
1685      }
1686
1687      *colour = ((r & 0x1f) | ((g & 0x1f) << 5) | ((b & 0x1f) << 10));
1688   }
1689}
1690
16081691/*********************************************
16091692 * snes_refresh_scanline()
16101693 *
16111694 * Redraw the current line.
16121695 *********************************************/
1696/*********************************************
1697 * Notice that in hires and pseudo hires modes,
1698 * i.e. when 512 different pixels are present
1699 * in a scanline, a crt TV monitor would end
1700 * up blending adjacent pixels. To mimic this,
1701 * we add a small (optional) hack which enters
1702 * only in the very last stage of the scanline
1703 * drawing and which simulates the TV by
1704 * replacing the exact pixel color with an
1705 * average of the current and next pixel colors.
1706 * Credits (and thanks) to Blargg and Byuu for
1707 * the optimized averaging algorithm.
1708 *********************************************/
16131709
16141710static void snes_refresh_scanline( running_machine *machine, bitmap_t *bitmap, UINT16 curline )
16151711{
r7644r7645
16191715   struct SCANLINE *scanline1, *scanline2;
16201716   UINT16 c;
16211717   UINT16 prev_colour = 0;
1622   int average = input_port_read_safe(machine, "OPTIONS", 0) & 0x01;
1718   int blurring = input_port_read_safe(machine, "OPTIONS", 0) & 0x01;
16231719
16241720   profiler_mark_start(PROFILER_VIDEO);
16251721
r7644r7645
17261822            /* prepare the pixel from sub screen */
17271823            c = scanline2->buffer[x];
17281824
1729            /* in hires, subscreen pixels are blended as well: for each subscreen pixel, color math is applied if
1730                it had been applied to the previous mainscreen pixel. What happens at subscreen pixel 0 (which has no
1731                previous mainscreen pixel) is undocumented. Until more info are discovered, we (arbitrarily) apply to it
1732                the same color math as the *next* mainscreen pixel (i.e. mainscreen pixel 0) */
1825            /* in hires/pseudo-hires, subscreen pixels are blended as well: for each subscreen pixel, color math
1826                is applied if it had been applied to the previous mainscreen pixel. What happens at subscreen pixel 0
1827                (which has no previous mainscreen pixel) is undocumented. Until more info are discovered, we (arbitrarily)
1828                apply to it the same color math as the *next* mainscreen pixel (i.e. mainscreen pixel 0), which seems as good as
1829                any other choice */
17331830            if (x == 0 && !scanline1->blend_exception[0] && snes_ppu.layer[scanline1->layer[0]].color_math)
17341831               snes_draw_blend(0, &c, snes_ppu.prevent_color_math, snes_ppu.clip_to_black, 1);
17351832            else if (x > 0  && !scanline1->blend_exception[x - 1] && snes_ppu.layer[scanline1->layer[x - 1]].color_math)
r7644r7645
17381835            tmp_col[0] = c;
17391836
17401837            /* average the first pixel if required, or draw it directly*/
1741            if (average)
1742               c = (prev_colour + tmp_col[0] - ((prev_colour ^ tmp_col[0]) & 0x0421)) >> 1;
1838            if (blurring)
1839               c = (prev_colour + tmp_col[0] - ((prev_colour ^ tmp_col[0]) & 0x0421)) >> 1;   // Hack code to mimic TV pixel blurring
17431840            else
17441841               c = tmp_col[0];
17451842
r7644r7645
17501847            *BITMAP_ADDR32(bitmap, curline, x * 2 + 0) = MAKE_RGB(pal5bit(r), pal5bit(g), pal5bit(b));
17511848            prev_colour = tmp_col[0];
17521849
1753
17541850            /* average the second pixel if required, or draw it directly*/
1755            if (average)
1756               c = (prev_colour + tmp_col[1] - ((prev_colour ^ tmp_col[1]) & 0x0421)) >> 1;
1851            if (blurring)
1852               c = (prev_colour + tmp_col[1] - ((prev_colour ^ tmp_col[1]) & 0x0421)) >> 1;   // Hack code to mimic TV pixel blurring
17571853            else
17581854               c = tmp_col[1];
17591855

Previous 15994 Revisions Next


© 1998-2018 The MESS Team