1 // license:BSD-3-Clause
2 // copyright-holders:Nicola Salmoria, David Haywood
3 // Video System Sprites
4 // todo:
5 //  update drivers which call multiple priority passes to use the pdrawgfx version (aerofgt, gstriker)
6 
7 //  according to gstriker this is probably the Fujitsu CG10103
8 
9 // Aero Fighters (newer hardware)
10 // Quiz & Variety Sukusuku Inufuku
11 // 3 On 3 Dunk Madness
12 // Super Slams
13 // Formula 1 Grand Prix 2
14 // (Lethal) Crash Race
15 // Grand Striker
16 // V Goal Soccer
17 // Tecmo World Cup '94
18 // Tao Taido
19 
20 /* old notes */
21 
22 /*** Fujitsu CG10103 **********************************************/
23 
24 /*
25     Fujitsu CG10103 sprite generator
26     --------------------------------
27 
28 - Tile based
29 - 16x16 4bpp tiles
30 - Up to 7x7 in each block
31 - 5 bit of palette selection for the mixer
32 - Scaling (x/y)
33 - Flipping
34 - Indipendent sorting list
35 - 1 bit of pri for the mixer
36 
37 Note that this chip can be connected to a VS9210 which adds a level of indirection for
38 tile numbers. Basically, the VS9210 indirects the tilet number through a table in its attached
39 memory, before accessing the ROMs.
40 
41 
42     Sorting list format (VideoRAM offset 0)
43     ---------------------------------------
44 
45 de-- ---f ssss ssss
46 
47 e=end of list
48 f=sprite present in this position
49 s=sprite index
50 d=disable sprite?
51 
52 
53 TODO:
54 Priorities should be right, but they probably need to be orthogonal with the mixer priorities.
55 Zoom factor is not correct, the scale is probably non-linear
56 Horizontal wrapping is just a hack. The chip probably calculates if it needs to draw the sprite at the
57   normal position, or wrapped along X/Y.
58 Abstracts the VS9210
59 
60 */
61 
62 #include "emu.h"
63 #include "vsystem_spr.h"
64 #include "screen.h"
65 
66 
67 DEFINE_DEVICE_TYPE(VSYSTEM_SPR, vsystem_spr_device, "vsystem_spr", "Video System VS9108 Sprites")
68 
vsystem_spr_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)69 vsystem_spr_device::vsystem_spr_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
70 	: device_t(mconfig, VSYSTEM_SPR, tag, owner, clock)
71 	, m_newtilecb(*this, DEVICE_SELF, FUNC(vsystem_spr_device::tile_callback_noindirect))
72 	, m_xoffs(0)
73 	, m_yoffs(0)
74 	, m_pdraw(false)
75 	, m_pal_mask(0x3f)
76 	, m_gfx_region(-1)
77 	, m_transpen(15)
78 	, m_pal_base(0)
79 	, m_curr_sprite()
80 	, m_gfxdecode(*this, finder_base::DUMMY_TAG)
81 {
82 }
83 
tile_callback_noindirect(uint32_t tile)84 uint32_t vsystem_spr_device::tile_callback_noindirect(uint32_t tile)
85 {
86 	return tile;
87 }
88 
device_start()89 void vsystem_spr_device::device_start()
90 {
91 	// bind our handler
92 	m_newtilecb.resolve();
93 
94 	save_item(NAME(m_pal_base));
95 
96 	save_item(NAME(m_curr_sprite.ox));
97 	save_item(NAME(m_curr_sprite.xsize));
98 	save_item(NAME(m_curr_sprite.zoomx));
99 	save_item(NAME(m_curr_sprite.oy));
100 	save_item(NAME(m_curr_sprite.ysize));
101 	save_item(NAME(m_curr_sprite.zoomy));
102 	save_item(NAME(m_curr_sprite.flipx));
103 	save_item(NAME(m_curr_sprite.flipy));
104 	save_item(NAME(m_curr_sprite.color));
105 	save_item(NAME(m_curr_sprite.pri));
106 	save_item(NAME(m_curr_sprite.map));
107 }
108 
device_reset()109 void vsystem_spr_device::device_reset()
110 {
111 }
112 
get(uint16_t const * ram)113 void vsystem_spr_device::sprite_attributes::get(uint16_t const *ram)
114 {
115 	/*
116 	    attr_start + 0x0000
117 	    ---- ---x xxxx xxxx oy
118 	    ---- xxx- ---- ---- ysize
119 	    xxxx ---- ---- ---- zoomy
120 
121 	    attr_start + 0x0001
122 	    ---- ---x xxxx xxxx ox
123 	    ---- xxx- ---- ---- xsize
124 	    xxxx ---- ---- ---- zoomx
125 
126 	    attr_start + 0x0002
127 	    -x-- ---- ---- ---- flipx
128 	    x--- ---- ---- ---- flipy
129 	    --xx xxxx ---- ---- color
130 	    --xx ---- ---- ---- priority? (upper color bits)
131 	    ---- ---- ---- ---x map start (msb)
132 
133 	    attr_start + 0x0003
134 	    xxxx xxxx xxxx xxxx map start (lsb)
135 	*/
136 
137 	oy =    (ram[0] & 0x01ff);
138 	ysize = (ram[0] & 0x0e00) >> 9;
139 	zoomy = (ram[0] & 0xf000) >> 12;
140 
141 	ox =    (ram[1] & 0x01ff);
142 	xsize = (ram[1] & 0x0e00) >> 9;
143 	zoomx = (ram[1] & 0xf000) >> 12;
144 
145 	flipx = (ram[2] & 0x4000);
146 	flipy = (ram[2] & 0x8000);
147 	color = (ram[2] & 0x3f00) >> 8;
148 	pri   = (ram[2] & 0x3000) >> 12;
149 	map   = (ram[2] & 0x0001) << 16;
150 
151 	map  |= (ram[3] & 0xffff);
152 }
153 
154 
common_sprite_drawgfx(bitmap_ind16 & bitmap,const rectangle & cliprect,bitmap_ind8 & priority_bitmap)155 void vsystem_spr_device::common_sprite_drawgfx(bitmap_ind16 &bitmap, const rectangle &cliprect, bitmap_ind8 &priority_bitmap)
156 {
157 	gfx_element *gfx = m_gfxdecode->gfx(m_gfx_region);
158 	int priority_mask = 0x00;
159 
160 	m_curr_sprite.oy += m_yoffs;
161 	m_curr_sprite.ox += m_xoffs;
162 
163 	if (m_pdraw)
164 	{
165 		switch (m_curr_sprite.pri)
166 		{
167 			default:
168 			case 0: priority_mask = 0x00; break;
169 			case 3: priority_mask = 0xfe; break;
170 			case 2: priority_mask = 0xfc; break;
171 			case 1: priority_mask = 0xf0; break;
172 		}
173 	}
174 
175 	m_curr_sprite.zoomx = 32 - m_curr_sprite.zoomx;
176 	m_curr_sprite.zoomy = 32 - m_curr_sprite.zoomy;
177 
178 	int ystart, yend, yinc;
179 
180 	if (!m_curr_sprite.flipy) { ystart = 0; yend = m_curr_sprite.ysize+1; yinc = 1; }
181 	else                    { ystart = m_curr_sprite.ysize; yend = -1; yinc = -1; }
182 
183 	int ycnt = ystart;
184 	while (ycnt != yend)
185 	{
186 		int xstart, xend, xinc;
187 
188 		if (!m_curr_sprite.flipx) { xstart = 0; xend = m_curr_sprite.xsize+1; xinc = 1; }
189 		else                    { xstart = m_curr_sprite.xsize; xend = -1; xinc = -1; }
190 
191 		int xcnt = xstart;
192 		while (xcnt != xend)
193 		{
194 			int startno = m_newtilecb(m_curr_sprite.map++);
195 			if (m_pdraw)
196 			{
197 				gfx->prio_zoom_transpen(bitmap,cliprect, startno, m_curr_sprite.color + m_pal_base, m_curr_sprite.flipx, m_curr_sprite.flipy, m_curr_sprite.ox + xcnt * m_curr_sprite.zoomx/2,        m_curr_sprite.oy + ycnt * m_curr_sprite.zoomy/2,        m_curr_sprite.zoomx << 11, m_curr_sprite.zoomy << 11, priority_bitmap, priority_mask, m_transpen);
198 				gfx->prio_zoom_transpen(bitmap,cliprect, startno, m_curr_sprite.color + m_pal_base, m_curr_sprite.flipx, m_curr_sprite.flipy, -0x200+m_curr_sprite.ox + xcnt * m_curr_sprite.zoomx/2, m_curr_sprite.oy + ycnt * m_curr_sprite.zoomy/2,        m_curr_sprite.zoomx << 11, m_curr_sprite.zoomy << 11, priority_bitmap, priority_mask, m_transpen);
199 				gfx->prio_zoom_transpen(bitmap,cliprect, startno, m_curr_sprite.color + m_pal_base, m_curr_sprite.flipx, m_curr_sprite.flipy, m_curr_sprite.ox + xcnt * m_curr_sprite.zoomx/2,        -0x200+m_curr_sprite.oy + ycnt * m_curr_sprite.zoomy/2, m_curr_sprite.zoomx << 11, m_curr_sprite.zoomy << 11, priority_bitmap, priority_mask, m_transpen);
200 				gfx->prio_zoom_transpen(bitmap,cliprect, startno, m_curr_sprite.color + m_pal_base, m_curr_sprite.flipx, m_curr_sprite.flipy, -0x200+m_curr_sprite.ox + xcnt * m_curr_sprite.zoomx/2, -0x200+m_curr_sprite.oy + ycnt * m_curr_sprite.zoomy/2, m_curr_sprite.zoomx << 11, m_curr_sprite.zoomy << 11, priority_bitmap, priority_mask, m_transpen);
201 			}
202 			else
203 			{
204 				gfx->zoom_transpen(bitmap,cliprect, startno, m_curr_sprite.color + m_pal_base, m_curr_sprite.flipx, m_curr_sprite.flipy, m_curr_sprite.ox + xcnt * m_curr_sprite.zoomx/2,        m_curr_sprite.oy + ycnt * m_curr_sprite.zoomy/2,        m_curr_sprite.zoomx << 11, m_curr_sprite.zoomy << 11, m_transpen);
205 				gfx->zoom_transpen(bitmap,cliprect, startno, m_curr_sprite.color + m_pal_base, m_curr_sprite.flipx, m_curr_sprite.flipy, -0x200+m_curr_sprite.ox + xcnt * m_curr_sprite.zoomx/2, m_curr_sprite.oy + ycnt * m_curr_sprite.zoomy/2,        m_curr_sprite.zoomx << 11, m_curr_sprite.zoomy << 11, m_transpen);
206 				gfx->zoom_transpen(bitmap,cliprect, startno, m_curr_sprite.color + m_pal_base, m_curr_sprite.flipx, m_curr_sprite.flipy, m_curr_sprite.ox + xcnt * m_curr_sprite.zoomx/2,        -0x200+m_curr_sprite.oy + ycnt * m_curr_sprite.zoomy/2, m_curr_sprite.zoomx << 11, m_curr_sprite.zoomy << 11, m_transpen);
207 				gfx->zoom_transpen(bitmap,cliprect, startno, m_curr_sprite.color + m_pal_base, m_curr_sprite.flipx, m_curr_sprite.flipy, -0x200+m_curr_sprite.ox + xcnt * m_curr_sprite.zoomx/2, -0x200+m_curr_sprite.oy + ycnt * m_curr_sprite.zoomy/2, m_curr_sprite.zoomx << 11, m_curr_sprite.zoomy << 11, m_transpen);
208 			}
209 			xcnt+=xinc;
210 		}
211 		ycnt+=yinc;
212 	}
213 
214 }
215 
216 
217 
draw_sprites(uint16_t const * spriteram,int spriteram_bytes,screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect,int prihack_mask,int prihack_val)218 void vsystem_spr_device::draw_sprites(uint16_t const *spriteram, int spriteram_bytes, screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int prihack_mask, int prihack_val )
219 {
220 	int offs;
221 	int end = 0;
222 
223 	// find the end of the list
224 	for (offs = 0; offs < (spriteram_bytes / 16 ); offs++)
225 	{
226 		if (spriteram[offs] & 0x4000) break;
227 	}
228 	end = offs;
229 
230 	// decide our drawing order (if we're using pdrawgfx we must go in reverse)
231 	int first, last, inc;
232 	if (m_pdraw)
233 	{
234 		first = end - 1;
235 		last = -1;
236 		inc = -1;
237 	}
238 	else
239 	{
240 		first = 0;
241 		last = end;
242 		inc = 1;
243 	}
244 
245 	// draw
246 	offs = first;
247 	while (offs != last)
248 	{
249 		if ((spriteram[offs] & 0x8000) == 0x0000)
250 		{
251 			int attr_start;
252 
253 			attr_start = 4 * (spriteram[offs] & 0x03ff);
254 
255 			m_curr_sprite.get(&spriteram[attr_start]);
256 
257 			m_curr_sprite.color &= m_pal_mask;
258 
259 			// hack for aero fighters and other which still call us multiple times with different priorities instead of using the pdrawgfx version
260 			if (prihack_mask != -1)
261 			{
262 				if ((m_curr_sprite.pri & prihack_mask) == prihack_val)
263 					common_sprite_drawgfx(bitmap, cliprect, screen.priority());
264 			}
265 			else
266 			{
267 				common_sprite_drawgfx(bitmap, cliprect, screen.priority());
268 			}
269 		}
270 
271 		offs+=inc;
272 	}
273 }
274