Refactor sprite rendering
This commit is contained in:
		
							parent
							
								
									361f106393
								
							
						
					
					
						commit
						54484ff131
					
				
					 1 changed files with 83 additions and 75 deletions
				
			
		
							
								
								
									
										152
									
								
								video.cc
									
										
									
									
									
								
							
							
						
						
									
										152
									
								
								video.cc
									
										
									
									
									
								
							|  | @ -638,6 +638,8 @@ static u8 obj_alpha_count[160]; | ||||||
| typedef struct { | typedef struct { | ||||||
|   s32 obj_x, obj_y; |   s32 obj_x, obj_y; | ||||||
|   s32 obj_w, obj_h; |   s32 obj_w, obj_h; | ||||||
|  |   u32 attr1, attr2; | ||||||
|  |   bool is_double; | ||||||
| } t_sprite; | } t_sprite; | ||||||
| 
 | 
 | ||||||
| // Renders a tile row (8 pixels) for a regular (non-affine) object/sprite.
 | // Renders a tile row (8 pixels) for a regular (non-affine) object/sprite.
 | ||||||
|  | @ -708,8 +710,8 @@ static inline void render_obj_tile_Nbpp(bool forcebld, | ||||||
| // Renders a regular sprite (non-affine) row to screen.
 | // Renders a regular sprite (non-affine) row to screen.
 | ||||||
| // delta_x is the object X coordinate referenced from the window start.
 | // delta_x is the object X coordinate referenced from the window start.
 | ||||||
| // cnt is the maximum number of pixels to draw, honoring window, obj width, etc.
 | // cnt is the maximum number of pixels to draw, honoring window, obj width, etc.
 | ||||||
| template <typename stype, rendtype rdtype, bool is8bpp, bool hflip> | template <typename stype, rendtype rdtype, bool forcebld, bool is8bpp, bool hflip> | ||||||
| static void render_object(bool forcebld, | static void render_object( | ||||||
|   s32 delta_x, u32 cnt, stype *dst_ptr, u32 tile_offset, u16 palette |   s32 delta_x, u32 cnt, stype *dst_ptr, u32 tile_offset, u16 palette | ||||||
| ) { | ) { | ||||||
|   // Tile size in bytes for each mode
 |   // Tile size in bytes for each mode
 | ||||||
|  | @ -759,9 +761,9 @@ static void render_object(bool forcebld, | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| // Renders an affine sprite row to screen.
 | // Renders an affine sprite row to screen.
 | ||||||
| template <typename stype, rendtype rdtype, bool is8bpp, bool rotate> | template <typename stype, rendtype rdtype, bool forcebld, bool is8bpp, bool rotate> | ||||||
| static void render_affine_object( | static void render_affine_object( | ||||||
|   const t_sprite *obji, bool forcebld, const t_affp *affp, bool is_double, |   const t_sprite *obji, const t_affp *affp, bool is_double, | ||||||
|   u32 start, u32 end, stype *dst_ptr, u32 base_tile, u16 palette |   u32 start, u32 end, stype *dst_ptr, u32 base_tile, u16 palette | ||||||
| ) { | ) { | ||||||
|   // Tile size in bytes for each mode
 |   // Tile size in bytes for each mode
 | ||||||
|  | @ -879,6 +881,68 @@ static void render_affine_object( | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // Renders a single sprite on the current scanline
 | ||||||
|  | template <typename stype, rendtype rdtype, bool forcebld, bool is8bpp> | ||||||
|  | inline static void render_sprite( | ||||||
|  |   const t_sprite *obji, bool is_affine, u32 start, u32 end, stype *scanline | ||||||
|  | ) { | ||||||
|  |   s32 vcount = read_ioreg(REG_VCOUNT); | ||||||
|  |   bool obj1dmap = read_ioreg(REG_DISPCNT) & 0x40; | ||||||
|  |   const u32 msk = is8bpp && !obj1dmap ? 0x3FE : 0x3FF; | ||||||
|  |   const u32 base_tile = (obji->attr2 & msk) * 32; | ||||||
|  | 
 | ||||||
|  |   if (is_affine) { | ||||||
|  |     u32 pnum = (obji->attr1 >> 9) & 0x1f; | ||||||
|  |     const t_affp *affp_base = (t_affp*)oam_ram; | ||||||
|  |     const t_affp *affp = &affp_base[pnum]; | ||||||
|  |     u16 pal = is8bpp ? 0 : ((obji->attr2 >> 8) & 0xF0); | ||||||
|  | 
 | ||||||
|  |     if (affp->dy == 0)     // No rotation happening (just scale)
 | ||||||
|  |       render_affine_object<stype, rdtype, forcebld, is8bpp, false>(obji, affp, obji->is_double, start, end, scanline, base_tile, pal); | ||||||
|  |     else                   // Full rotation and scaling
 | ||||||
|  |       render_affine_object<stype, rdtype, forcebld, is8bpp, true>(obji, affp, obji->is_double, start, end, scanline, base_tile, pal); | ||||||
|  |   } else { | ||||||
|  |     // The object could be out of the window, check and skip.
 | ||||||
|  |     if (obji->obj_x >= (signed)end || obji->obj_x + obji->obj_w <= (signed)start) | ||||||
|  |       return; | ||||||
|  | 
 | ||||||
|  |     // Non-affine objects can be flipped on both edges.
 | ||||||
|  |     bool hflip = obji->attr1 & 0x1000; | ||||||
|  |     bool vflip = obji->attr1 & 0x2000; | ||||||
|  | 
 | ||||||
|  |     // Calulate the vertical offset (row) to be displayed. Account for vflip.
 | ||||||
|  |     u32 voffset = vflip ? obji->obj_y + obji->obj_h - vcount - 1 : vcount - obji->obj_y; | ||||||
|  | 
 | ||||||
|  |     // Calculate base tile for the object (points to the row to be drawn).
 | ||||||
|  |     u32 tile_bsize  = is8bpp ? tile_size_8bpp : tile_size_4bpp; | ||||||
|  |     u32 tile_bwidth = is8bpp ? tile_width_8bpp : tile_width_4bpp; | ||||||
|  |     u32 obj_pitch = obj1dmap ? (obji->obj_w / 8) * tile_bsize : 1024; | ||||||
|  |     u32 hflip_off = hflip ? ((obji->obj_w / 8) - 1) * tile_bsize : 0; | ||||||
|  | 
 | ||||||
|  |     // Calculate the pointer to the tile.
 | ||||||
|  |     const u32 tile_offset = | ||||||
|  |       base_tile +                    // Char offset
 | ||||||
|  |       (voffset / 8) * obj_pitch +    // Select tile row offset
 | ||||||
|  |       (voffset % 8) * tile_bwidth +  // Skip tile rows
 | ||||||
|  |       hflip_off;                     // Account for horizontal flip
 | ||||||
|  | 
 | ||||||
|  |     // Make everything relative to start
 | ||||||
|  |     s32 obj_x_offset  = obji->obj_x - start; | ||||||
|  |     u32 clipped_width = obj_x_offset >= 0 ? obji->obj_w : obji->obj_w + obj_x_offset; | ||||||
|  |     u32 max_range = obj_x_offset >= 0 ? end - obji->obj_x : end - start; | ||||||
|  |     u32 max_draw = MIN(max_range, clipped_width); | ||||||
|  | 
 | ||||||
|  |     // Render the object scanline using the correct mode.
 | ||||||
|  |     // (in 4bpp mode calculate the palette number)
 | ||||||
|  |     u16 pal = is8bpp ? 0 : ((obji->attr2 >> 8) & 0xF0); | ||||||
|  | 
 | ||||||
|  |     if (hflip) | ||||||
|  |       render_object<stype, rdtype, forcebld, is8bpp, true>(obj_x_offset, max_draw, &scanline[start], tile_offset, pal); | ||||||
|  |     else | ||||||
|  |       render_object<stype, rdtype, forcebld, is8bpp, false>(obj_x_offset, max_draw, &scanline[start], tile_offset, pal); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // Renders objects on a scanline for a given priority.
 | // Renders objects on a scanline for a given priority.
 | ||||||
| template <typename stype, rendtype rdtype, conditional_render_function copyfn> | template <typename stype, rendtype rdtype, conditional_render_function copyfn> | ||||||
| static void render_scanline_objs( | static void render_scanline_objs( | ||||||
|  | @ -886,7 +950,6 @@ static void render_scanline_objs( | ||||||
| ) { | ) { | ||||||
|   stype *scanline = (stype*)raw_ptr; |   stype *scanline = (stype*)raw_ptr; | ||||||
|   s32 vcount = read_ioreg(REG_VCOUNT); |   s32 vcount = read_ioreg(REG_VCOUNT); | ||||||
|   bool obj1dmap = read_ioreg(REG_DISPCNT) & 0x40; |  | ||||||
|   u32 objn; |   u32 objn; | ||||||
|   u32 objcnt = obj_priority_count[priority][vcount]; |   u32 objcnt = obj_priority_count[priority][vcount]; | ||||||
|   u8 *objlist = obj_priority_list[priority][vcount]; |   u8 *objlist = obj_priority_list[priority][vcount]; | ||||||
|  | @ -899,30 +962,28 @@ static void render_scanline_objs( | ||||||
| 
 | 
 | ||||||
|     u16 obj_attr0 = eswap16(oamentry->attr0); |     u16 obj_attr0 = eswap16(oamentry->attr0); | ||||||
|     u16 obj_attr1 = eswap16(oamentry->attr1); |     u16 obj_attr1 = eswap16(oamentry->attr1); | ||||||
|     u16 obj_attr2 = eswap16(oamentry->attr2); |  | ||||||
|     u16 obj_shape = obj_attr0 >> 14; |     u16 obj_shape = obj_attr0 >> 14; | ||||||
|     u16 obj_size = (obj_attr1 >> 14); |     u16 obj_size = (obj_attr1 >> 14); | ||||||
|     bool is_affine = obj_attr0 & 0x100; |     bool is_affine = obj_attr0 & 0x100; | ||||||
|     bool is_8bpp = obj_attr0 & 0x2000; |  | ||||||
|     bool is_double = obj_attr0 & 0x200; |  | ||||||
|     bool is_trans = ((obj_attr0 >> 10) & 0x3) == OBJ_MOD_SEMITRAN; |     bool is_trans = ((obj_attr0 >> 10) & 0x3) == OBJ_MOD_SEMITRAN; | ||||||
|  |     bool is_8bpp = (obj_attr0 & 0x2000) != 0; | ||||||
| 
 | 
 | ||||||
|     t_sprite obji = { |     t_sprite obji = { | ||||||
|       .obj_x = (s32)(obj_attr1 << 23) >> 23, |       .obj_x = (s32)(obj_attr1 << 23) >> 23, | ||||||
|       .obj_y = obj_attr0 & 0xFF, |       .obj_y = obj_attr0 & 0xFF, | ||||||
|       .obj_w = obj_dim_table[obj_shape][obj_size][0], |       .obj_w = obj_dim_table[obj_shape][obj_size][0], | ||||||
|       .obj_h = obj_dim_table[obj_shape][obj_size][1] |       .obj_h = obj_dim_table[obj_shape][obj_size][1], | ||||||
|  |       .attr1 = obj_attr1, | ||||||
|  |       .attr2 = eswap16(oamentry->attr2), | ||||||
|  |       .is_double = (obj_attr0 & 0x200) != 0, | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     s32 obj_maxw = (is_affine && is_double) ? obji.obj_w * 2 : obji.obj_w; |     s32 obj_maxw = (is_affine && obji.is_double) ? obji.obj_w * 2 : obji.obj_w; | ||||||
| 
 | 
 | ||||||
|     // The object could be out of the window, check and skip.
 |     // The object could be out of the window, check and skip.
 | ||||||
|     if (obji.obj_x >= (signed)end || obji.obj_x + obj_maxw <= (signed)start) |     if (obji.obj_x >= (signed)end || obji.obj_x + obj_maxw <= (signed)start) | ||||||
|       continue; |       continue; | ||||||
| 
 | 
 | ||||||
|     const u32 msk = is_8bpp && !obj1dmap ? 0x3FE : 0x3FF; |  | ||||||
|     const u32 base_tile =  (obj_attr2 & msk) * 32; |  | ||||||
| 
 |  | ||||||
|     // ST-OBJs force 1st target bit (forced blending)
 |     // ST-OBJs force 1st target bit (forced blending)
 | ||||||
|     bool forcebld = is_trans && rdtype != FULLCOLOR; |     bool forcebld = is_trans && rdtype != FULLCOLOR; | ||||||
| 
 | 
 | ||||||
|  | @ -941,69 +1002,16 @@ static void render_scanline_objs( | ||||||
|       copyfn(sec_start, sec_end, tmp_ptr, obj_enable); |       copyfn(sec_start, sec_end, tmp_ptr, obj_enable); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (is_affine) { |  | ||||||
|       u32 pnum = (obj_attr1 >> 9) & 0x1f; |  | ||||||
|       const t_affp *affp_base = (t_affp*)oam_ram; |  | ||||||
|       const t_affp *affp = &affp_base[pnum]; |  | ||||||
|       u16 palette = (obj_attr2 >> 8) & 0xF0; |  | ||||||
| 
 |  | ||||||
|       if (affp->dy == 0) {   // No rotation happening (just scale)
 |  | ||||||
|         if (is_8bpp) |  | ||||||
|           render_affine_object<stype, rdtype, true, false>(&obji, forcebld, affp, is_double, start, end, scanline, base_tile, 0); |  | ||||||
|         else |  | ||||||
|           render_affine_object<stype, rdtype, false, false>(&obji, forcebld, affp, is_double, start, end, scanline, base_tile, palette); |  | ||||||
|       } else {               // Full rotation and scaling
 |  | ||||||
|         if (is_8bpp) |  | ||||||
|           render_affine_object<stype, rdtype, true, true>(&obji, forcebld, affp, is_double, start, end, scanline, base_tile, 0); |  | ||||||
|         else |  | ||||||
|           render_affine_object<stype, rdtype, false, true>(&obji, forcebld, affp, is_double, start, end, scanline, base_tile, palette); |  | ||||||
|       } |  | ||||||
|     } else { |  | ||||||
|       // The object could be out of the window, check and skip.
 |  | ||||||
|       if (obji.obj_x >= (signed)end || obji.obj_x + obji.obj_w <= (signed)start) |  | ||||||
|         continue; |  | ||||||
| 
 |  | ||||||
|       // Non-affine objects can be flipped on both edges.
 |  | ||||||
|       bool hflip = obj_attr1 & 0x1000; |  | ||||||
|       bool vflip = obj_attr1 & 0x2000; |  | ||||||
| 
 |  | ||||||
|       // Calulate the vertical offset (row) to be displayed. Account for vflip.
 |  | ||||||
|       u32 voffset = vflip ? obji.obj_y + obji.obj_h - vcount - 1 : vcount - obji.obj_y; |  | ||||||
| 
 |  | ||||||
|       // Calculate base tile for the object (points to the row to be drawn).
 |  | ||||||
|       u32 tile_bsize  = is_8bpp ? tile_size_8bpp : tile_size_4bpp; |  | ||||||
|       u32 tile_bwidth = is_8bpp ? tile_width_8bpp : tile_width_4bpp; |  | ||||||
|       u32 obj_pitch = obj1dmap ? (obji.obj_w / 8) * tile_bsize : 1024; |  | ||||||
|       u32 hflip_off = hflip ? ((obji.obj_w / 8) - 1) * tile_bsize : 0; |  | ||||||
| 
 |  | ||||||
|       // Calculate the pointer to the tile.
 |  | ||||||
|       const u32 tile_offset = |  | ||||||
|         base_tile +                    // Char offset
 |  | ||||||
|         (voffset / 8) * obj_pitch +    // Select tile row offset
 |  | ||||||
|         (voffset % 8) * tile_bwidth +  // Skip tile rows
 |  | ||||||
|         hflip_off;                     // Account for horizontal flip
 |  | ||||||
| 
 |  | ||||||
|       // Make everything relative to start
 |  | ||||||
|       s32 obj_x_offset  = obji.obj_x - start; |  | ||||||
|       u32 clipped_width = obj_x_offset >= 0 ? obji.obj_w : obji.obj_w + obj_x_offset; |  | ||||||
|       u32 max_range = obj_x_offset >= 0 ? end - obji.obj_x : end - start; |  | ||||||
|       u32 max_draw = MIN(max_range, clipped_width); |  | ||||||
| 
 |  | ||||||
|       // Render the object scanline using the correct mode.
 |  | ||||||
|     if (is_8bpp) { |     if (is_8bpp) { | ||||||
|         if (hflip) |       if (forcebld) | ||||||
|           render_object<stype, rdtype, true, true>(forcebld, obj_x_offset, max_draw, &scanline[start], tile_offset, 0); |         render_sprite<stype, rdtype, true, true>(&obji, is_affine, start, end, scanline); | ||||||
|       else |       else | ||||||
|           render_object<stype, rdtype, true, false>(forcebld, obj_x_offset, max_draw, &scanline[start], tile_offset, 0); |         render_sprite<stype, rdtype, false, true>(&obji, is_affine, start, end, scanline); | ||||||
|     } else { |     } else { | ||||||
|         // In 4bpp mode calculate the palette number
 |       if (forcebld) | ||||||
|         u16 palette = (obj_attr2 >> 8) & 0xF0; |         render_sprite<stype, rdtype, true, false>(&obji, is_affine, start, end, scanline); | ||||||
| 
 |  | ||||||
|         if (hflip) |  | ||||||
|           render_object<stype, rdtype, false, true>(forcebld, obj_x_offset, max_draw, &scanline[start], tile_offset, palette); |  | ||||||
|       else |       else | ||||||
|           render_object<stype, rdtype, false, false>(forcebld, obj_x_offset, max_draw, &scanline[start], tile_offset, palette); |         render_sprite<stype, rdtype, false, false>(&obji, is_affine, start, end, scanline); | ||||||
|       } |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue