summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/video/vsystem_spr.c
blob: e68f6ab53f0af17d60e80bb1a70ebe27240076b5 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
// Video System Sprites
// todo:
//  update drivers which call multiple priority passes to use the pdrawgfx version (aerofgt, gstriker)

//  according to gstriker this is probably the Fujitsu CG10103

// Aero Fighters (newer hardware)
// Quiz & Variety Sukusuku Inufuku
// 3 On 3 Dunk Madness
// Super Slams
// Formula 1 Grand Prix 2
// (Lethal) Crash Race
// Grand Striker
// V Goal Soccer
// Tecmo World Cup '94
// Tao Taido

/* old notes */

/*** Fujitsu CG10103 **********************************************/

/*
    Fujitsu CG10103 sprite generator
    --------------------------------

- Tile based
- 16x16 4bpp tiles
- Up to 7x7 in each block
- 5 bit of palette selection for the mixer
- Scaling (x/y)
- Flipping
- Indipendent sorting list
- 1 bit of pri for the mixer

Note that this chip can be connected to a VS9210 which adds a level of indirection for
tile numbers. Basically, the VS9210 indirects the tilet number through a table in its attached
memory, before accessing the ROMs.


    Sorting list format (VideoRAM offset 0)
    ---------------------------------------

de-- ---f ssss ssss

e=end of list
f=sprite present in this position
s=sprite index
d=disable sprite?


TODO:
Priorities should be right, but they probably need to be orthogonal with the mixer priorities.
Zoom factor is not correct, the scale is probably non-linear
Horizontal wrapping is just a hack. The chip probably calculates if it needs to draw the sprite at the
  normal position, or wrapped along X/Y.
Abstracts the VS9210

*/



#include "emu.h"
#include "vsystem_spr.h"






const device_type VSYSTEM_SPR = &device_creator<vsystem_spr_device>;

vsystem_spr_device::vsystem_spr_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
	: device_t(mconfig, VSYSTEM_SPR, "vsystem_spr_device", tag, owner, clock)
{
	m_transpen = 15;
	m_pal_base = 0;
	m_xoffs = 0;
	m_yoffs = 0;
	m_pdraw = false;
	m_gfx_region = -1;
	m_pal_mask = 0x3f;

	m_newtilecb =  vsystem_tile_indirection_delegate(FUNC(vsystem_spr_device::tile_callback_noindirect), this);
}

UINT32 vsystem_spr_device::tile_callback_noindirect(UINT32 tile)
{
	return tile;
}


// static
void vsystem_spr_device::set_tile_indirect_cb(device_t &device,vsystem_tile_indirection_delegate newtilecb)
{
	vsystem_spr_device &dev = downcast<vsystem_spr_device &>(device);
	dev.m_newtilecb = newtilecb;
}


// static
void vsystem_spr_device::set_offsets(device_t &device, int xoffs, int yoffs)
{
	vsystem_spr_device &dev = downcast<vsystem_spr_device &>(device);
	dev.m_xoffs = xoffs;
	dev.m_yoffs = yoffs;
}

// static
void vsystem_spr_device::set_pdraw(device_t &device, bool pdraw)
{
	vsystem_spr_device &dev = downcast<vsystem_spr_device &>(device);
	dev.m_pdraw = pdraw;
}

// static
void vsystem_spr_device::CG10103_set_gfx_region(device_t &device, int gfx_region)
{
	vsystem_spr_device &dev = downcast<vsystem_spr_device &>(device);
	dev.m_gfx_region = gfx_region;
}

// static
void vsystem_spr_device::CG10103_set_pal_base(device_t &device, int pal_base)
{
	vsystem_spr_device &dev = downcast<vsystem_spr_device &>(device);
	dev.m_pal_base = pal_base;
}

// static
void vsystem_spr_device::set_pal_mask(device_t &device, int pal_mask)
{
	vsystem_spr_device &dev = downcast<vsystem_spr_device &>(device);
	dev.m_pal_mask = pal_mask;
}

// static
void vsystem_spr_device::CG10103_set_transpen(device_t &device, int transpen)
{
	vsystem_spr_device &dev = downcast<vsystem_spr_device &>(device);
	dev.m_transpen = transpen;
}


void vsystem_spr_device::device_start()
{
	// bind our handler
	m_newtilecb.bind_relative_to(*owner());
}

void vsystem_spr_device::device_reset()
{

}

void vsystem_spr_device::get_sprite_attributes(UINT16* ram)
{
	/*
        attr_start + 0x0000
        ---- ---x xxxx xxxx oy
        ---- xxx- ---- ---- ysize
        xxxx ---- ---- ---- zoomy

        attr_start + 0x0001
        ---- ---x xxxx xxxx ox
        ---- xxx- ---- ---- xsize
        xxxx ---- ---- ---- zoomx

        attr_start + 0x0002
        -x-- ---- ---- ---- flipx
        x--- ---- ---- ---- flipy
        --xx xxxx ---- ---- color
        --xx ---- ---- ---- priority? (upper color bits)
        ---- ---- ---- ---x map start (msb)

        attr_start + 0x0003
        xxxx xxxx xxxx xxxx map start (lsb)
    */

	curr_sprite.oy =    (ram[0] & 0x01ff);
	curr_sprite.ysize = (ram[0] & 0x0e00) >> 9;
	curr_sprite.zoomy = (ram[0] & 0xf000) >> 12;

	curr_sprite.ox =    (ram[1] & 0x01ff);
	curr_sprite.xsize = (ram[1] & 0x0e00) >> 9;
	curr_sprite.zoomx = (ram[1] & 0xf000) >> 12;

	curr_sprite.flipx = (ram[2] & 0x4000);
	curr_sprite.flipy = (ram[2] & 0x8000);
	curr_sprite.color = (ram[2] & 0x3f00) >> 8;
	curr_sprite.pri   = (ram[2] & 0x3000) >> 12;
	curr_sprite.map   = (ram[2] & 0x0001) << 16;

	curr_sprite.map  |= (ram[3] & 0xffff);
}


void vsystem_spr_device::common_sprite_drawgfx( running_machine &machine, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
	gfx_element *gfx = machine.gfx[m_gfx_region];
	int priority_mask = 0x00;

	curr_sprite.oy += m_yoffs;
	curr_sprite.ox += m_xoffs;

	if (m_pdraw)
	{
		switch (curr_sprite.pri)
		{
			default:
			case 0:	priority_mask = 0x00; break;
			case 3:	priority_mask = 0xfe; break;
			case 2:	priority_mask = 0xfc; break;
			case 1:	priority_mask = 0xf0; break;
		}
	}

	curr_sprite.zoomx = 32 - curr_sprite.zoomx;
	curr_sprite.zoomy = 32 - curr_sprite.zoomy;

	int ystart, yend, yinc;
	
	if (!curr_sprite.flipy)	{ ystart = 0; yend = curr_sprite.ysize+1; yinc = 1; }
	else                    { ystart = curr_sprite.ysize; yend = -1; yinc = -1; }

	int ycnt = ystart;
	while (ycnt != yend)
	{
		int xstart, xend, xinc;

		if (!curr_sprite.flipx)	{ xstart = 0; xend = curr_sprite.xsize+1; xinc = 1; }
		else                    { xstart = curr_sprite.xsize; xend = -1; xinc = -1; }

		int xcnt = xstart;
		while (xcnt != xend)
		{
			int startno = m_newtilecb(curr_sprite.map++);
			if (m_pdraw)
			{
				pdrawgfxzoom_transpen(bitmap, cliprect, gfx, startno, curr_sprite.color + m_pal_base, curr_sprite.flipx, curr_sprite.flipy, curr_sprite.ox + xcnt * curr_sprite.zoomx/2,        curr_sprite.oy + ycnt * curr_sprite.zoomy/2,        curr_sprite.zoomx << 11, curr_sprite.zoomy << 11, machine.priority_bitmap,priority_mask, m_transpen);
				pdrawgfxzoom_transpen(bitmap, cliprect, gfx, startno, curr_sprite.color + m_pal_base, curr_sprite.flipx, curr_sprite.flipy, -0x200+curr_sprite.ox + xcnt * curr_sprite.zoomx/2, curr_sprite.oy + ycnt * curr_sprite.zoomy/2,        curr_sprite.zoomx << 11, curr_sprite.zoomy << 11, machine.priority_bitmap,priority_mask, m_transpen);		
				pdrawgfxzoom_transpen(bitmap, cliprect, gfx, startno, curr_sprite.color + m_pal_base, curr_sprite.flipx, curr_sprite.flipy, curr_sprite.ox + xcnt * curr_sprite.zoomx/2,        -0x200+curr_sprite.oy + ycnt * curr_sprite.zoomy/2, curr_sprite.zoomx << 11, curr_sprite.zoomy << 11, machine.priority_bitmap,priority_mask, m_transpen);
				pdrawgfxzoom_transpen(bitmap, cliprect, gfx, startno, curr_sprite.color + m_pal_base, curr_sprite.flipx, curr_sprite.flipy, -0x200+curr_sprite.ox + xcnt * curr_sprite.zoomx/2, -0x200+curr_sprite.oy + ycnt * curr_sprite.zoomy/2, curr_sprite.zoomx << 11, curr_sprite.zoomy << 11, machine.priority_bitmap,priority_mask, m_transpen);		
			}
			else
			{
				drawgfxzoom_transpen(bitmap, cliprect, gfx, startno, curr_sprite.color + m_pal_base, curr_sprite.flipx, curr_sprite.flipy, curr_sprite.ox + xcnt * curr_sprite.zoomx/2,        curr_sprite.oy + ycnt * curr_sprite.zoomy/2,        curr_sprite.zoomx << 11, curr_sprite.zoomy << 11, m_transpen);
				drawgfxzoom_transpen(bitmap, cliprect, gfx, startno, curr_sprite.color + m_pal_base, curr_sprite.flipx, curr_sprite.flipy, -0x200+curr_sprite.ox + xcnt * curr_sprite.zoomx/2, curr_sprite.oy + ycnt * curr_sprite.zoomy/2,        curr_sprite.zoomx << 11, curr_sprite.zoomy << 11, m_transpen);		
				drawgfxzoom_transpen(bitmap, cliprect, gfx, startno, curr_sprite.color + m_pal_base, curr_sprite.flipx, curr_sprite.flipy, curr_sprite.ox + xcnt * curr_sprite.zoomx/2,        -0x200+curr_sprite.oy + ycnt * curr_sprite.zoomy/2, curr_sprite.zoomx << 11, curr_sprite.zoomy << 11, m_transpen);
				drawgfxzoom_transpen(bitmap, cliprect, gfx, startno, curr_sprite.color + m_pal_base, curr_sprite.flipx, curr_sprite.flipy, -0x200+curr_sprite.ox + xcnt * curr_sprite.zoomx/2, -0x200+curr_sprite.oy + ycnt * curr_sprite.zoomy/2, curr_sprite.zoomx << 11, curr_sprite.zoomy << 11, m_transpen);		
			}
			xcnt+=xinc;
		}
		ycnt+=yinc;
	}
	
}



void vsystem_spr_device::draw_sprites( UINT16* spriteram, int spriteram_bytes, running_machine &machine, bitmap_ind16 &bitmap, const rectangle &cliprect, int prihack_mask, int prihack_val )
{
	int offs;
	int end = 0;

	// find the end of the list
	for (offs = 0; offs < (spriteram_bytes / 16 ); offs++)
	{
		if (spriteram[offs] & 0x4000) break;
	}
	end = offs;

	// decide our drawing order (if we're using pdrawgfx we must go in reverse)
	int first, last, inc;
	if (m_pdraw)
	{
		first = end - 1;
		last = -1;
		inc = -1;
	}
	else
	{
		first = 0;
		last = end;
		inc = 1;
	}

	// draw
	offs = first;
	while (offs != last)
	{
		if ((spriteram[offs] & 0x8000) == 0x0000)
		{
			int attr_start;

			attr_start = 4 * (spriteram[offs] & 0x03ff);

			get_sprite_attributes(&spriteram[attr_start]);

			curr_sprite.color &= m_pal_mask;

			// hack for aero fighters and other which still call us multiple times with different priorities instead of using the pdrawgfx version
			if (prihack_mask != -1)
			{
				if ((curr_sprite.pri & prihack_mask) == prihack_val)
					common_sprite_drawgfx(machine, bitmap, cliprect);
			}
			else
			{
				common_sprite_drawgfx(machine, bitmap, cliprect);
			}
		}

		offs+=inc;
	}
}