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