1 // license:BSD-3-Clause
2 // copyright-holders:Luca Elia,David Haywood,Paul Priest
3 /*
4     Jaleco Megasystem 32 sprite hardware
5 
6     TODO:
7         verify hardware configuration
8 
9     used by:
10     ms32.cpp
11     bnstars.cpp (Dual screen configuration)
12     tetrisp2.cpp (Slightly different - no zoom, etc)
13 
14     Sprite format (16 byte per each sprite):
15     Offset Bits              Description
16            fedcba98 76543210
17     00     -xxxxxxx -------- Palette Select (some hardwares with YUV color format)
18            -------- xxxx---- Priority
19            -------- -----x-- Visible
20            -------- ------x- Flip Y
21            -------- -------x Flip X
22     02     xxxxxxxx -------- Source Y offset (1 pixel each)
23            -------- xxxxxxxx Source X offset (1 pixel each)
24     04     xxxx---- -------- Palette Select (most of hardwares)
25            ----xxxx xxxxxxxx Source Texture Select (each texture is 256 x 256 pixels)
26     06     xxxxxxxx -------- Source Width - 1 (1 pixel each)
27            -------- xxxxxxxx Source Height - 1 (1 pixel each)
28     08     ------xx xxxxxxxx Y (10 bits signed)
29     0a     -----xxx xxxxxxxx X (11 bits signed)
30     0c     xxxxxxxx xxxxxxxx Zoom X (some hardware disabled this, 0x200 = 50%, 0x100 = 100%, 0x80 = 200%)*
31     0e     xxxxxxxx xxxxxxxx Zoom Y (some hardware disabled this, 0x200 = 50%, 0x100 = 100%, 0x80 = 200%)*
32 
33     * : Source position add, 8.8 Fixed point
34 */
35 
36 #include "emu.h"
37 #include "ms32_sprite.h"
38 #include "drawgfxt.ipp"
39 
40 DEFINE_DEVICE_TYPE(JALECO_MEGASYSTEM32_SPRITE, ms32_sprite_device, "ms32spr", "Jaleco Megasystem 32 Sprite hardware")
41 
ms32_sprite_device(const machine_config & mconfig,const char * tag,device_t * owner,u32 clock)42 ms32_sprite_device::ms32_sprite_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
43 	: device_t(mconfig, JALECO_MEGASYSTEM32_SPRITE, tag, owner, clock)
44 	, device_gfx_interface(mconfig, *this, nullptr)
45 	, m_color_base(0)
46 	, m_color_entries(0x10)
47 {
48 }
49 
50 /*************************************
51  *
52  *  Graphics definitions
53  *
54  *************************************/
55 
56 /* sprites are contained in 256x256 "tiles" */
57 static const u32 sprite_xoffset[256] =
58 {
59 	STEP8(8*8*8*0,    8), STEP8(8*8*8*1,    8), STEP8(8*8*8*2,    8), STEP8(8*8*8*3,    8),
60 	STEP8(8*8*8*4,    8), STEP8(8*8*8*5,    8), STEP8(8*8*8*6,    8), STEP8(8*8*8*7,    8),
61 	STEP8(8*8*8*8,    8), STEP8(8*8*8*9,    8), STEP8(8*8*8*10,   8), STEP8(8*8*8*11,   8),
62 	STEP8(8*8*8*12,   8), STEP8(8*8*8*13,   8), STEP8(8*8*8*14,   8), STEP8(8*8*8*15,   8),
63 	STEP8(8*8*8*16,   8), STEP8(8*8*8*17,   8), STEP8(8*8*8*18,   8), STEP8(8*8*8*19,   8),
64 	STEP8(8*8*8*20,   8), STEP8(8*8*8*21,   8), STEP8(8*8*8*22,   8), STEP8(8*8*8*23,   8),
65 	STEP8(8*8*8*24,   8), STEP8(8*8*8*25,   8), STEP8(8*8*8*26,   8), STEP8(8*8*8*27,   8),
66 	STEP8(8*8*8*28,   8), STEP8(8*8*8*29,   8), STEP8(8*8*8*30,   8), STEP8(8*8*8*31,   8)
67 };
68 static const u32 sprite_yoffset[256] =
69 {
70 	STEP8(8*8*8*0,  8*8), STEP8(8*8*8*32, 8*8), STEP8(8*8*8*64, 8*8), STEP8(8*8*8*96, 8*8),
71 	STEP8(8*8*8*128,8*8), STEP8(8*8*8*160,8*8), STEP8(8*8*8*192,8*8), STEP8(8*8*8*224,8*8),
72 	STEP8(8*8*8*256,8*8), STEP8(8*8*8*288,8*8), STEP8(8*8*8*320,8*8), STEP8(8*8*8*352,8*8),
73 	STEP8(8*8*8*384,8*8), STEP8(8*8*8*416,8*8), STEP8(8*8*8*448,8*8), STEP8(8*8*8*480,8*8),
74 	STEP8(8*8*8*512,8*8), STEP8(8*8*8*544,8*8), STEP8(8*8*8*576,8*8), STEP8(8*8*8*608,8*8),
75 	STEP8(8*8*8*640,8*8), STEP8(8*8*8*672,8*8), STEP8(8*8*8*704,8*8), STEP8(8*8*8*736,8*8),
76 	STEP8(8*8*8*768,8*8), STEP8(8*8*8*800,8*8), STEP8(8*8*8*832,8*8), STEP8(8*8*8*864,8*8),
77 	STEP8(8*8*8*896,8*8), STEP8(8*8*8*928,8*8), STEP8(8*8*8*960,8*8), STEP8(8*8*8*992,8*8)
78 };
79 static const gfx_layout spritelayout =
80 {
81 	256, 256,
82 	RGN_FRAC(1,1),
83 	8,
84 	{ STEP8(0,1) },
85 	EXTENDED_XOFFS,
86 	EXTENDED_YOFFS,
87 	256*256*8,
88 	sprite_xoffset,
89 	sprite_yoffset
90 };
91 
92 GFXDECODE_MEMBER(ms32_sprite_device::gfxinfo)
93 	GFXDECODE_DEVICE(DEVICE_SELF, 0, spritelayout, 0, 16)
94 GFXDECODE_END
95 
device_start()96 void ms32_sprite_device::device_start()
97 {
98 	// decode our graphics
99 	decode_gfx(gfxinfo);
100 	gfx(0)->set_colorbase(m_color_base);
101 	gfx(0)->set_colors(m_color_entries);
102 }
103 
extract_parameters(bool has_zoom,bool is_yuv,const u16 * ram,bool & disable,u8 & pri,bool & flipx,bool & flipy,u32 & code,u32 & color,u8 & tx,u8 & ty,u16 & srcwidth,u16 & srcheight,s32 & sx,s32 & sy,u16 & incx,u16 & incy)104 void ms32_sprite_device::extract_parameters(bool has_zoom, bool is_yuv, const u16 *ram, bool &disable, u8 &pri, bool &flipx, bool &flipy, u32 &code, u32 &color, u8 &tx, u8 &ty, u16 &srcwidth, u16 &srcheight, s32 &sx, s32 &sy, u16 &incx, u16 &incy)
105 {
106 	const u16 attr =   ram[0];
107 	pri            = ( attr & 0x00f0);
108 	disable        = (~attr & 0x0004);
109 
110 	flipx          =   attr & 1;
111 	flipy          =   attr & 2;
112 	code           =   ram[1];
113 	color          =   ram[2];
114 	tx             =   (code >> 0) & 0xff;
115 	ty             =   (code >> 8) & 0xff;
116 
117 	code           =   (color & 0x0fff);
118 	// encoded to first word when YUV sprites are used
119 	if (is_yuv)
120 		color      =   (attr & 0x7f00) >> 8;
121 	else
122 		color      =   (color >> 12) & 0xf;
123 	const u16 size =   ram[3];
124 
125 	srcwidth       =   ((size >> 0) & 0xff) + 1;
126 	srcheight      =   ((size >> 8) & 0xff) + 1;
127 
128 	sx             =   (ram[5] & 0x3ff) - (ram[5] & 0x400);
129 	sy             =   (ram[4] & 0x1ff) - (ram[4] & 0x200);
130 
131 	if (has_zoom)
132 	{
133 		incx       =   (ram[6] & 0xffff);
134 		incy       =   (ram[7] & 0xffff);
135 	}
136 	else
137 	{
138 		incx       =   0x100;
139 		incy       =   0x100;
140 
141 		// hack for tetrisp2?
142 		if (srcwidth > 0x100 - tx)
143 			srcwidth = 0x100 - tx;
144 
145 		if (srcheight > 0x100 - ty)
146 			srcheight = 0x100 - ty;
147 	}
148 }
149 
150 /***************************************************************************
151     DRAWGFX IMPLEMENTATIONS
152 ***************************************************************************/
153 
154 /*-------------------------------------------------
155     opaque - render a gfx element with
156     no transparency
157 -------------------------------------------------*/
158 
opaque(bitmap_ind16 & dest,const rectangle & cliprect,u32 code,u32 color,int flipx,int flipy,s32 destx,s32 desty,u32 tx,u32 ty,u32 srcwidth,u32 srcheight)159 void ms32_sprite_device::opaque(bitmap_ind16 &dest, const rectangle &cliprect,
160 		u32 code, u32 color, int flipx, int flipy, s32 destx, s32 desty, u32 tx, u32 ty, u32 srcwidth, u32 srcheight)
161 {
162 	// non-clip case
163 	if (tx == 0 && ty == 0 && srcwidth == 0x100 && srcheight == 0x100)
164 		gfx(0)->opaque(dest, cliprect, code, color, flipx, flipy, destx, desty);
165 
166 	color = gfx(0)->colorbase() + gfx(0)->granularity() * (color % gfx(0)->colors());
167 	code %= gfx(0)->elements();
168 	draw_sprite_core(dest, cliprect, code, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, [color](u16 &destp, const u8 &srcp) { PIXEL_OP_REBASE_OPAQUE(destp, srcp); });
169 }
170 
opaque(bitmap_rgb32 & dest,const rectangle & cliprect,u32 code,u32 color,int flipx,int flipy,s32 destx,s32 desty,u32 tx,u32 ty,u32 srcwidth,u32 srcheight)171 void ms32_sprite_device::opaque(bitmap_rgb32 &dest, const rectangle &cliprect,
172 		u32 code, u32 color, int flipx, int flipy, s32 destx, s32 desty, u32 tx, u32 ty, u32 srcwidth, u32 srcheight)
173 {
174 	// non-clip case
175 	if (tx == 0 && ty == 0 && srcwidth == 0x100 && srcheight == 0x100)
176 		gfx(0)->opaque(dest, cliprect, code, color, flipx, flipy, destx, desty);
177 
178 	const pen_t *paldata = palette().pens() + gfx(0)->colorbase() + gfx(0)->granularity() * (color % gfx(0)->colors());
179 	code %= gfx(0)->elements();
180 	draw_sprite_core(dest, cliprect, code, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, [paldata](u32 &destp, const u8 &srcp) { PIXEL_OP_REMAP_OPAQUE(destp, srcp); });
181 }
182 
183 /*-------------------------------------------------
184     transpen - render a gfx element with
185     a single transparent pen
186 -------------------------------------------------*/
187 
transpen(bitmap_ind16 & dest,const rectangle & cliprect,u32 code,u32 color,int flipx,int flipy,s32 destx,s32 desty,u32 tx,u32 ty,u32 srcwidth,u32 srcheight,u32 trans_pen)188 void ms32_sprite_device::transpen(bitmap_ind16 &dest, const rectangle &cliprect,
189 		u32 code, u32 color, int flipx, int flipy, s32 destx, s32 desty, u32 tx, u32 ty, u32 srcwidth, u32 srcheight,
190 		u32 trans_pen)
191 {
192 	// non-clip case
193 	if (tx == 0 && ty == 0 && srcwidth == 0x100 && srcheight == 0x100)
194 		gfx(0)->transpen(dest, cliprect, code, color, flipx, flipy, destx, desty, trans_pen);
195 
196 	// special case invalid pens to opaque
197 	if (trans_pen > 0xff)
198 		return opaque(dest, cliprect, code, color, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight);
199 
200 	// use pen usage to optimize
201 	code %= gfx(0)->elements();
202 	if (gfx(0)->has_pen_usage())
203 	{
204 		// fully transparent; do nothing
205 		u32 usage = gfx(0)->pen_usage(code);
206 		if ((usage & ~(1 << trans_pen)) == 0)
207 			return;
208 
209 		// fully opaque; draw as such
210 		if ((usage & (1 << trans_pen)) == 0)
211 			return opaque(dest, cliprect, code, color, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight);
212 	}
213 
214 	// render
215 	color = gfx(0)->colorbase() + gfx(0)->granularity() * (color % gfx(0)->colors());
216 	draw_sprite_core(dest, cliprect, code, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, [trans_pen, color](u16 &destp, const u8 &srcp) { PIXEL_OP_REBASE_TRANSPEN(destp, srcp); });
217 }
218 
transpen(bitmap_rgb32 & dest,const rectangle & cliprect,u32 code,u32 color,int flipx,int flipy,s32 destx,s32 desty,u32 tx,u32 ty,u32 srcwidth,u32 srcheight,u32 trans_pen)219 void ms32_sprite_device::transpen(bitmap_rgb32 &dest, const rectangle &cliprect,
220 		u32 code, u32 color, int flipx, int flipy, s32 destx, s32 desty, u32 tx, u32 ty, u32 srcwidth, u32 srcheight,
221 		u32 trans_pen)
222 {
223 	// non-clip case
224 	if (tx == 0 && ty == 0 && srcwidth == 0x100 && srcheight == 0x100)
225 		gfx(0)->transpen(dest, cliprect, code, color, flipx, flipy, destx, desty, trans_pen);
226 
227 	// special case invalid pens to opaque
228 	if (trans_pen > 0xff)
229 		return opaque(dest, cliprect, code, color, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight);
230 
231 	// use pen usage to optimize
232 	code %= gfx(0)->elements();
233 	if (gfx(0)->has_pen_usage())
234 	{
235 		// fully transparent; do nothing
236 		u32 usage = gfx(0)->pen_usage(code);
237 		if ((usage & ~(1 << trans_pen)) == 0)
238 			return;
239 
240 		// fully opaque; draw as such
241 		if ((usage & (1 << trans_pen)) == 0)
242 			return opaque(dest, cliprect, code, color, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight);
243 	}
244 
245 	// render
246 	const pen_t *paldata = palette().pens() + gfx(0)->colorbase() + gfx(0)->granularity() * (color % gfx(0)->colors());
247 	draw_sprite_core(dest, cliprect, code, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, [trans_pen, paldata](u32 &destp, const u8 &srcp) { PIXEL_OP_REMAP_TRANSPEN(destp, srcp); });
248 }
249 
250 
251 /*-------------------------------------------------
252     transpen_raw - render a gfx element
253     with a single transparent pen and no color
254     lookups
255 -------------------------------------------------*/
256 
transpen_raw(bitmap_ind16 & dest,const rectangle & cliprect,u32 code,u32 color,int flipx,int flipy,s32 destx,s32 desty,u32 tx,u32 ty,u32 srcwidth,u32 srcheight,u32 trans_pen)257 void ms32_sprite_device::transpen_raw(bitmap_ind16 &dest, const rectangle &cliprect,
258 		u32 code, u32 color, int flipx, int flipy, s32 destx, s32 desty, u32 tx, u32 ty, u32 srcwidth, u32 srcheight,
259 		u32 trans_pen)
260 {
261 	// non-clip case
262 	if (tx == 0 && ty == 0 && srcwidth == 0x100 && srcheight == 0x100)
263 		gfx(0)->transpen_raw(dest, cliprect, code, color, flipx, flipy, destx, desty, trans_pen);
264 
265 	// early out if completely transparent
266 	code %= gfx(0)->elements();
267 	if (gfx(0)->has_pen_usage() && (gfx(0)->pen_usage(code) & ~(1 << trans_pen)) == 0)
268 		return;
269 
270 	// render
271 	draw_sprite_core(dest, cliprect, code, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, [trans_pen, color](u16 &destp, const u8 &srcp) { PIXEL_OP_REBASE_TRANSPEN(destp, srcp); });
272 }
273 
transpen_raw(bitmap_rgb32 & dest,const rectangle & cliprect,u32 code,u32 color,int flipx,int flipy,s32 destx,s32 desty,u32 tx,u32 ty,u32 srcwidth,u32 srcheight,u32 trans_pen)274 void ms32_sprite_device::transpen_raw(bitmap_rgb32 &dest, const rectangle &cliprect,
275 		u32 code, u32 color, int flipx, int flipy, s32 destx, s32 desty, u32 tx, u32 ty, u32 srcwidth, u32 srcheight,
276 		u32 trans_pen)
277 {
278 	// non-clip case
279 	if (tx == 0 && ty == 0 && srcwidth == 0x100 && srcheight == 0x100)
280 		gfx(0)->transpen_raw(dest, cliprect, code, color, flipx, flipy, destx, desty, trans_pen);
281 
282 	// early out if completely transparent
283 	code %= gfx(0)->elements();
284 	if (gfx(0)->has_pen_usage() && (gfx(0)->pen_usage(code) & ~(1 << trans_pen)) == 0)
285 		return;
286 
287 	// render
288 	draw_sprite_core(dest, cliprect, code, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, [trans_pen, color](u32 &destp, const u8 &srcp) { PIXEL_OP_REBASE_TRANSPEN(destp, srcp); });
289 }
290 
291 /***************************************************************************
292     DRAWGFXZOOM IMPLEMENTATIONS
293 ***************************************************************************/
294 
295 /*-------------------------------------------------
296     zoom_opaque - render a scaled gfx
297     element with no transparency
298 -------------------------------------------------*/
299 
zoom_opaque(bitmap_ind16 & dest,const rectangle & cliprect,u32 code,u32 color,int flipx,int flipy,s32 destx,s32 desty,u32 tx,u32 ty,u32 srcwidth,u32 srcheight,u32 incx,u32 incy)300 void ms32_sprite_device::zoom_opaque(bitmap_ind16 &dest, const rectangle &cliprect,
301 		u32 code, u32 color, int flipx, int flipy, s32 destx, s32 desty, u32 tx, u32 ty, u32 srcwidth, u32 srcheight,
302 		u32 incx, u32 incy)
303 {
304 	// non-zoom case
305 	if (incx == 0x100 && incy == 0x100)
306 		return opaque(dest, cliprect, code, color, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight);
307 
308 	// render
309 	color = gfx(0)->colorbase() + gfx(0)->granularity() * (color % gfx(0)->colors());
310 	code %= gfx(0)->elements();
311 	draw_sprite_zoom_core(dest, cliprect, code, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, incx, incy, [color](u16 &destp, const u8 &srcp) { PIXEL_OP_REBASE_OPAQUE(destp, srcp); });
312 }
313 
zoom_opaque(bitmap_rgb32 & dest,const rectangle & cliprect,u32 code,u32 color,int flipx,int flipy,s32 destx,s32 desty,u32 tx,u32 ty,u32 srcwidth,u32 srcheight,u32 incx,u32 incy)314 void ms32_sprite_device::zoom_opaque(bitmap_rgb32 &dest, const rectangle &cliprect,
315 		u32 code, u32 color, int flipx, int flipy, s32 destx, s32 desty, u32 tx, u32 ty, u32 srcwidth, u32 srcheight,
316 		u32 incx, u32 incy)
317 {
318 	// non-zoom case
319 	if (incx == 0x100 && incy == 0x100)
320 		return opaque(dest, cliprect, code, color, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight);
321 
322 	// render
323 	const pen_t *paldata = palette().pens() + gfx(0)->colorbase() + gfx(0)->granularity() * (color % gfx(0)->colors());
324 	code %= gfx(0)->elements();
325 	draw_sprite_zoom_core(dest, cliprect, code, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, incx, incy, [paldata](u32 &destp, const u8 &srcp) { PIXEL_OP_REMAP_OPAQUE(destp, srcp); });
326 }
327 
328 
329 /*-------------------------------------------------
330     zoom_transpen - render a scaled gfx
331     element with a single transparent pen
332 -------------------------------------------------*/
333 
zoom_transpen(bitmap_ind16 & dest,const rectangle & cliprect,u32 code,u32 color,int flipx,int flipy,s32 destx,s32 desty,u32 tx,u32 ty,u32 srcwidth,u32 srcheight,u32 incx,u32 incy,u32 trans_pen)334 void ms32_sprite_device::zoom_transpen(bitmap_ind16 &dest, const rectangle &cliprect,
335 		u32 code, u32 color, int flipx, int flipy, s32 destx, s32 desty, u32 tx, u32 ty, u32 srcwidth, u32 srcheight,
336 		u32 incx, u32 incy, u32 trans_pen)
337 {
338 	// non-zoom case
339 	if (incx == 0x100 && incy == 0x100)
340 		return transpen(dest, cliprect, code, color, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, trans_pen);
341 
342 	// special case invalid pens to opaque
343 	if (trans_pen > 0xff)
344 		return zoom_opaque(dest, cliprect, code, color, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, incx, incy);
345 
346 	// use pen usage to optimize
347 	code %= gfx(0)->elements();
348 	if (gfx(0)->has_pen_usage())
349 	{
350 		// fully transparent; do nothing
351 		u32 usage = gfx(0)->pen_usage(code);
352 		if ((usage & ~(1 << trans_pen)) == 0)
353 			return;
354 
355 		// fully opaque; draw as such
356 		if ((usage & (1 << trans_pen)) == 0)
357 			return zoom_opaque(dest, cliprect, code, color, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, incx, incy);
358 	}
359 
360 	// render
361 	color = gfx(0)->colorbase() + gfx(0)->granularity() * (color % gfx(0)->colors());
362 	draw_sprite_zoom_core(dest, cliprect, code, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, incx, incy, [trans_pen, color](u16 &destp, const u8 &srcp) { PIXEL_OP_REBASE_TRANSPEN(destp, srcp); });
363 }
364 
zoom_transpen(bitmap_rgb32 & dest,const rectangle & cliprect,u32 code,u32 color,int flipx,int flipy,s32 destx,s32 desty,u32 tx,u32 ty,u32 srcwidth,u32 srcheight,u32 incx,u32 incy,u32 trans_pen)365 void ms32_sprite_device::zoom_transpen(bitmap_rgb32 &dest, const rectangle &cliprect,
366 		u32 code, u32 color, int flipx, int flipy, s32 destx, s32 desty, u32 tx, u32 ty, u32 srcwidth, u32 srcheight,
367 		u32 incx, u32 incy, u32 trans_pen)
368 {
369 	// non-zoom case
370 	if (incx == 0x100 && incy == 0x100)
371 		return transpen(dest, cliprect, code, color, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, trans_pen);
372 
373 	// special case invalid pens to opaque
374 	if (trans_pen > 0xff)
375 		return zoom_opaque(dest, cliprect, code, color, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, incx, incy);
376 
377 	// use pen usage to optimize
378 	code %= gfx(0)->elements();
379 	if (gfx(0)->has_pen_usage())
380 	{
381 		// fully transparent; do nothing
382 		u32 usage = gfx(0)->pen_usage(code);
383 		if ((usage & ~(1 << trans_pen)) == 0)
384 			return;
385 
386 		// fully opaque; draw as such
387 		if ((usage & (1 << trans_pen)) == 0)
388 			return zoom_opaque(dest, cliprect, code, color, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, incx, incy);
389 	}
390 
391 	// render
392 	const pen_t *paldata = palette().pens() + gfx(0)->colorbase() + gfx(0)->granularity() * (color % gfx(0)->colors());
393 	draw_sprite_zoom_core(dest, cliprect, code, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, incx, incy, [trans_pen, paldata](u32 &destp, const u8 &srcp) { PIXEL_OP_REMAP_TRANSPEN(destp, srcp); });
394 }
395 
396 
397 /*-------------------------------------------------
398     zoom_transpen_raw - render a scaled gfx
399     element with a single transparent pen and no
400     color lookups
401 -------------------------------------------------*/
402 
zoom_transpen_raw(bitmap_ind16 & dest,const rectangle & cliprect,u32 code,u32 color,int flipx,int flipy,s32 destx,s32 desty,u32 tx,u32 ty,u32 srcwidth,u32 srcheight,u32 incx,u32 incy,u32 trans_pen)403 void ms32_sprite_device::zoom_transpen_raw(bitmap_ind16 &dest, const rectangle &cliprect,
404 		u32 code, u32 color, int flipx, int flipy, s32 destx, s32 desty, u32 tx, u32 ty, u32 srcwidth, u32 srcheight,
405 		u32 incx, u32 incy, u32 trans_pen)
406 {
407 	// non-zoom case
408 	if (incx == 0x100 && incy == 0x100)
409 		return transpen_raw(dest, cliprect, code, color, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, trans_pen);
410 
411 	// early out if completely transparent
412 	code %= gfx(0)->elements();
413 	if (gfx(0)->has_pen_usage() && (gfx(0)->pen_usage(code) & ~(1 << trans_pen)) == 0)
414 		return;
415 
416 	// render
417 	draw_sprite_zoom_core(dest, cliprect, code, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, incx, incy, [trans_pen, color](u16 &destp, const u8 &srcp) { PIXEL_OP_REBASE_TRANSPEN(destp, srcp); });
418 }
419 
zoom_transpen_raw(bitmap_rgb32 & dest,const rectangle & cliprect,u32 code,u32 color,int flipx,int flipy,s32 destx,s32 desty,u32 tx,u32 ty,u32 srcwidth,u32 srcheight,u32 incx,u32 incy,u32 trans_pen)420 void ms32_sprite_device::zoom_transpen_raw(bitmap_rgb32 &dest, const rectangle &cliprect,
421 		u32 code, u32 color, int flipx, int flipy, s32 destx, s32 desty, u32 tx, u32 ty, u32 srcwidth, u32 srcheight,
422 		u32 incx, u32 incy, u32 trans_pen)
423 {
424 	// non-zoom case
425 	if (incx == 0x100 && incy == 0x100)
426 		return transpen_raw(dest, cliprect, code, color, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, trans_pen);
427 
428 	// early out if completely transparent
429 	code %= gfx(0)->elements();
430 	if (gfx(0)->has_pen_usage() && (gfx(0)->pen_usage(code) & ~(1 << trans_pen)) == 0)
431 		return;
432 
433 	// render
434 	draw_sprite_zoom_core(dest, cliprect, code, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, incx, incy, [trans_pen, color](u32 &destp, const u8 &srcp) { PIXEL_OP_REBASE_TRANSPEN(destp, srcp); });
435 }
436 
437 /***************************************************************************
438     PDRAWGFX IMPLEMENTATIONS
439 ***************************************************************************/
440 
441 /*-------------------------------------------------
442     prio_opaque - render a gfx element with
443     no transparency, checking against the priority
444     bitmap
445 -------------------------------------------------*/
446 
prio_opaque(bitmap_ind16 & dest,const rectangle & cliprect,u32 code,u32 color,int flipx,int flipy,s32 destx,s32 desty,u32 tx,u32 ty,u32 srcwidth,u32 srcheight,bitmap_ind8 & priority,u32 pmask)447 void ms32_sprite_device::prio_opaque(bitmap_ind16 &dest, const rectangle &cliprect,
448 		u32 code, u32 color, int flipx, int flipy, s32 destx, s32 desty, u32 tx, u32 ty, u32 srcwidth, u32 srcheight,
449 		bitmap_ind8 &priority, u32 pmask)
450 {
451 	// non-clip case
452 	if (tx == 0 && ty == 0 && srcwidth == 0x100 && srcheight == 0x100)
453 		gfx(0)->prio_opaque(dest, cliprect, code, color, flipx, flipy, destx, desty, priority, pmask);
454 
455 	// high bit of the mask is implicitly on
456 	pmask |= 1 << 31;
457 
458 	// render
459 	color = gfx(0)->colorbase() + gfx(0)->granularity() * (color % gfx(0)->colors());
460 	code %= gfx(0)->elements();
461 	draw_sprite_core(dest, cliprect, code, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, priority, [pmask, color](u16 &destp, u8 &pri, const u8 &srcp) { PIXEL_OP_REBASE_OPAQUE_PRIORITY(destp, pri, srcp); });
462 }
463 
prio_opaque(bitmap_rgb32 & dest,const rectangle & cliprect,u32 code,u32 color,int flipx,int flipy,s32 destx,s32 desty,u32 tx,u32 ty,u32 srcwidth,u32 srcheight,bitmap_ind8 & priority,u32 pmask)464 void ms32_sprite_device::prio_opaque(bitmap_rgb32 &dest, const rectangle &cliprect,
465 		u32 code, u32 color, int flipx, int flipy, s32 destx, s32 desty, u32 tx, u32 ty, u32 srcwidth, u32 srcheight,
466 		bitmap_ind8 &priority, u32 pmask)
467 {
468 	// non-clip case
469 	if (tx == 0 && ty == 0 && srcwidth == 0x100 && srcheight == 0x100)
470 		gfx(0)->prio_opaque(dest, cliprect, code, color, flipx, flipy, destx, desty, priority, pmask);
471 
472 	// high bit of the mask is implicitly on
473 	pmask |= 1 << 31;
474 
475 	// render
476 	const pen_t *paldata = palette().pens() + gfx(0)->colorbase() + gfx(0)->granularity() * (color % gfx(0)->colors());
477 	code %= gfx(0)->elements();
478 	draw_sprite_core(dest, cliprect, code, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, priority, [pmask, paldata](u32 &destp, u8 &pri, const u8 &srcp) { PIXEL_OP_REMAP_OPAQUE_PRIORITY(destp, pri, srcp); });
479 }
480 
481 
482 /*-------------------------------------------------
483     prio_transpen - render a gfx element with
484     a single transparent pen, checking against the
485     priority bitmap
486 -------------------------------------------------*/
487 
prio_transpen(bitmap_ind16 & dest,const rectangle & cliprect,u32 code,u32 color,int flipx,int flipy,s32 destx,s32 desty,u32 tx,u32 ty,u32 srcwidth,u32 srcheight,bitmap_ind8 & priority,u32 pmask,u32 trans_pen)488 void ms32_sprite_device::prio_transpen(bitmap_ind16 &dest, const rectangle &cliprect,
489 		u32 code, u32 color, int flipx, int flipy, s32 destx, s32 desty, u32 tx, u32 ty, u32 srcwidth, u32 srcheight,
490 		bitmap_ind8 &priority, u32 pmask, u32 trans_pen)
491 {
492 	// non-clip case
493 	if (tx == 0 && ty == 0 && srcwidth == 0x100 && srcheight == 0x100)
494 		gfx(0)->prio_transpen(dest, cliprect, code, color, flipx, flipy, destx, desty, priority, pmask, trans_pen);
495 
496 	// special case invalid pens to opaque
497 	if (trans_pen > 0xff)
498 		return prio_opaque(dest, cliprect, code, color, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, priority, pmask);
499 
500 	// use pen usage to optimize
501 	code %= gfx(0)->elements();
502 	if (gfx(0)->has_pen_usage())
503 	{
504 		// fully transparent; do nothing
505 		u32 usage = gfx(0)->pen_usage(code);
506 		if ((usage & ~(1 << trans_pen)) == 0)
507 			return;
508 
509 		// fully opaque; draw as such
510 		if ((usage & (1 << trans_pen)) == 0)
511 			return prio_opaque(dest, cliprect, code, color, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, priority, pmask);
512 	}
513 
514 	// high bit of the mask is implicitly on
515 	pmask |= 1 << 31;
516 
517 	// render
518 	color = gfx(0)->colorbase() + gfx(0)->granularity() * (color % gfx(0)->colors());
519 	draw_sprite_core(dest, cliprect, code, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, priority, [pmask, trans_pen, color](u16 &destp, u8 &pri, const u8 &srcp) { PIXEL_OP_REBASE_TRANSPEN_PRIORITY(destp, pri, srcp); });
520 }
521 
prio_transpen(bitmap_rgb32 & dest,const rectangle & cliprect,u32 code,u32 color,int flipx,int flipy,s32 destx,s32 desty,u32 tx,u32 ty,u32 srcwidth,u32 srcheight,bitmap_ind8 & priority,u32 pmask,u32 trans_pen)522 void ms32_sprite_device::prio_transpen(bitmap_rgb32 &dest, const rectangle &cliprect,
523 		u32 code, u32 color, int flipx, int flipy, s32 destx, s32 desty, u32 tx, u32 ty, u32 srcwidth, u32 srcheight,
524 		bitmap_ind8 &priority, u32 pmask, u32 trans_pen)
525 {
526 	// non-clip case
527 	if (tx == 0 && ty == 0 && srcwidth == 0x100 && srcheight == 0x100)
528 		gfx(0)->prio_transpen(dest, cliprect, code, color, flipx, flipy, destx, desty, priority, pmask, trans_pen);
529 
530 	// special case invalid pens to opaque
531 	if (trans_pen > 0xff)
532 		return prio_opaque(dest, cliprect, code, color, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, priority, pmask);
533 
534 	// use pen usage to optimize
535 	code %= gfx(0)->elements();
536 	if (gfx(0)->has_pen_usage())
537 	{
538 		// fully transparent; do nothing
539 		u32 usage = gfx(0)->pen_usage(code);
540 		if ((usage & ~(1 << trans_pen)) == 0)
541 			return;
542 
543 		// fully opaque; draw as such
544 		if ((usage & (1 << trans_pen)) == 0)
545 			return prio_opaque(dest, cliprect, code, color, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, priority, pmask);
546 	}
547 
548 	// high bit of the mask is implicitly on
549 	pmask |= 1 << 31;
550 
551 	// render
552 	const pen_t *paldata = palette().pens() + gfx(0)->colorbase() + gfx(0)->granularity() * (color % gfx(0)->colors());
553 	draw_sprite_core(dest, cliprect, code, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, priority, [pmask, trans_pen, paldata](u32 &destp, u8 &pri, const u8 &srcp) { PIXEL_OP_REMAP_TRANSPEN_PRIORITY(destp, pri, srcp); });
554 }
555 
556 /*-------------------------------------------------
557     priotranspen_raw - render a gfx element
558     with a single transparent pen and no color
559     lookups, checking against the priority bitmap
560 -------------------------------------------------*/
561 
prio_transpen_raw(bitmap_ind16 & dest,const rectangle & cliprect,u32 code,u32 color,int flipx,int flipy,s32 destx,s32 desty,u32 tx,u32 ty,u32 srcwidth,u32 srcheight,bitmap_ind8 & priority,u32 pmask,u32 trans_pen)562 void ms32_sprite_device::prio_transpen_raw(bitmap_ind16 &dest, const rectangle &cliprect,
563 		u32 code, u32 color, int flipx, int flipy, s32 destx, s32 desty, u32 tx, u32 ty, u32 srcwidth, u32 srcheight,
564 		bitmap_ind8 &priority, u32 pmask, u32 trans_pen)
565 {
566 	// non-clip case
567 	if (tx == 0 && ty == 0 && srcwidth == 0x100 && srcheight == 0x100)
568 		gfx(0)->prio_transpen_raw(dest, cliprect, code, color, flipx, flipy, destx, desty, priority, pmask, trans_pen);
569 
570 	// early out if completely transparent
571 	code %= gfx(0)->elements();
572 	if (gfx(0)->has_pen_usage() && (gfx(0)->pen_usage(code) & ~(1 << trans_pen)) == 0)
573 		return;
574 
575 	// high bit of the mask is implicitly on
576 	pmask |= 1 << 31;
577 
578 	// render
579 	draw_sprite_core(dest, cliprect, code, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, priority, [pmask, trans_pen, color](u16 &destp, u8 &pri, const u8 &srcp) { PIXEL_OP_REBASE_TRANSPEN_PRIORITY(destp, pri, srcp); });
580 }
581 
prio_transpen_raw(bitmap_rgb32 & dest,const rectangle & cliprect,u32 code,u32 color,int flipx,int flipy,s32 destx,s32 desty,u32 tx,u32 ty,u32 srcwidth,u32 srcheight,bitmap_ind8 & priority,u32 pmask,u32 trans_pen)582 void ms32_sprite_device::prio_transpen_raw(bitmap_rgb32 &dest, const rectangle &cliprect,
583 		u32 code, u32 color, int flipx, int flipy, s32 destx, s32 desty, u32 tx, u32 ty, u32 srcwidth, u32 srcheight,
584 		bitmap_ind8 &priority, u32 pmask, u32 trans_pen)
585 {
586 	// non-clip case
587 	if (tx == 0 && ty == 0 && srcwidth == 0x100 && srcheight == 0x100)
588 		gfx(0)->prio_transpen_raw(dest, cliprect, code, color, flipx, flipy, destx, desty, priority, pmask, trans_pen);
589 
590 	// early out if completely transparent
591 	code %= gfx(0)->elements();
592 	if (gfx(0)->has_pen_usage() && (gfx(0)->pen_usage(code) & ~(1 << trans_pen)) == 0)
593 		return;
594 
595 	// high bit of the mask is implicitly on
596 	pmask |= 1 << 31;
597 
598 	// render
599 	draw_sprite_core(dest, cliprect, code, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, priority, [pmask, trans_pen, color](u32 &destp, u8 &pri, const u8 &srcp) { PIXEL_OP_REBASE_TRANSPEN_PRIORITY(destp, pri, srcp); });
600 }
601 
602 /***************************************************************************
603     PDRAWGFXZOOM IMPLEMENTATIONS
604 ***************************************************************************/
605 
606 /*-------------------------------------------------
607     prio_zoom_opaque - render a scaled gfx
608     element with no transparency, checking against
609     the priority bitmap
610 -------------------------------------------------*/
611 
prio_zoom_opaque(bitmap_ind16 & dest,const rectangle & cliprect,u32 code,u32 color,int flipx,int flipy,s32 destx,s32 desty,u32 tx,u32 ty,u32 srcwidth,u32 srcheight,u32 incx,u32 incy,bitmap_ind8 & priority,u32 pmask)612 void ms32_sprite_device::prio_zoom_opaque(bitmap_ind16 &dest, const rectangle &cliprect,
613 		u32 code, u32 color, int flipx, int flipy, s32 destx, s32 desty, u32 tx, u32 ty, u32 srcwidth, u32 srcheight,
614 		u32 incx, u32 incy, bitmap_ind8 &priority, u32 pmask)
615 {
616 	// non-zoom case
617 	if (incx == 0x100 && incy == 0x100)
618 		return prio_opaque(dest, cliprect, code, color, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, priority, pmask);
619 
620 	// high bit of the mask is implicitly on
621 	pmask |= 1 << 31;
622 
623 	// render
624 	color = gfx(0)->colorbase() + gfx(0)->granularity() * (color % gfx(0)->colors());
625 	code %= gfx(0)->elements();
626 	draw_sprite_zoom_core(dest, cliprect, code, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, incx, incy, priority, [pmask, color](u16 &destp, u8 &pri, const u8 &srcp) { PIXEL_OP_REBASE_OPAQUE_PRIORITY(destp, pri, srcp); });
627 }
628 
prio_zoom_opaque(bitmap_rgb32 & dest,const rectangle & cliprect,u32 code,u32 color,int flipx,int flipy,s32 destx,s32 desty,u32 tx,u32 ty,u32 srcwidth,u32 srcheight,u32 incx,u32 incy,bitmap_ind8 & priority,u32 pmask)629 void ms32_sprite_device::prio_zoom_opaque(bitmap_rgb32 &dest, const rectangle &cliprect,
630 		u32 code, u32 color, int flipx, int flipy, s32 destx, s32 desty, u32 tx, u32 ty, u32 srcwidth, u32 srcheight,
631 		u32 incx, u32 incy, bitmap_ind8 &priority, u32 pmask)
632 {
633 	// non-zoom case
634 	if (incx == 0x100 && incy == 0x100)
635 		return prio_opaque(dest, cliprect, code, color, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, priority, pmask);
636 
637 	// high bit of the mask is implicitly on
638 	pmask |= 1 << 31;
639 
640 	// render
641 	const pen_t *paldata = palette().pens() + gfx(0)->colorbase() + gfx(0)->granularity() * (color % gfx(0)->colors());
642 	code %= gfx(0)->elements();
643 	draw_sprite_zoom_core(dest, cliprect, code, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, incx, incy, priority, [pmask, paldata](u32 &destp, u8 &pri, const u8 &srcp) { PIXEL_OP_REMAP_OPAQUE_PRIORITY(destp, pri, srcp); });
644 }
645 
646 
647 /*-------------------------------------------------
648     prio_zoom_transpen - render a scaled gfx
649     element with a single transparent pen,
650     checking against the priority bitmap
651 -------------------------------------------------*/
652 
prio_zoom_transpen(bitmap_ind16 & dest,const rectangle & cliprect,u32 code,u32 color,int flipx,int flipy,s32 destx,s32 desty,u32 tx,u32 ty,u32 srcwidth,u32 srcheight,u32 incx,u32 incy,bitmap_ind8 & priority,u32 pmask,u32 trans_pen)653 void ms32_sprite_device::prio_zoom_transpen(bitmap_ind16 &dest, const rectangle &cliprect,
654 		u32 code, u32 color, int flipx, int flipy, s32 destx, s32 desty, u32 tx, u32 ty, u32 srcwidth, u32 srcheight,
655 		u32 incx, u32 incy, bitmap_ind8 &priority, u32 pmask,
656 		u32 trans_pen)
657 {
658 	// non-zoom case
659 	if (incx == 0x100 && incy == 0x100)
660 		return prio_transpen(dest, cliprect, code, color, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, priority, pmask, trans_pen);
661 
662 	// special case invalid pens to opaque
663 	if (trans_pen > 0xff)
664 		return prio_zoom_opaque(dest, cliprect, code, color, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, incx, incy, priority, pmask);
665 
666 	// use pen usage to optimize
667 	code %= gfx(0)->elements();
668 	if (gfx(0)->has_pen_usage())
669 	{
670 		// fully transparent; do nothing
671 		u32 usage = gfx(0)->pen_usage(code);
672 		if ((usage & ~(1 << trans_pen)) == 0)
673 			return;
674 
675 		// fully opaque; draw as such
676 		if ((usage & (1 << trans_pen)) == 0)
677 			return prio_zoom_opaque(dest, cliprect, code, color, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, incx, incy, priority, pmask);
678 	}
679 
680 	// high bit of the mask is implicitly on
681 	pmask |= 1 << 31;
682 
683 	// render
684 	color = gfx(0)->colorbase() + gfx(0)->granularity() * (color % gfx(0)->colors());
685 	draw_sprite_zoom_core(dest, cliprect, code, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, incx, incy, priority, [pmask, trans_pen, color](u16 &destp, u8 &pri, const u8 &srcp) { PIXEL_OP_REBASE_TRANSPEN_PRIORITY(destp, pri, srcp); });
686 }
687 
prio_zoom_transpen(bitmap_rgb32 & dest,const rectangle & cliprect,u32 code,u32 color,int flipx,int flipy,s32 destx,s32 desty,u32 tx,u32 ty,u32 srcwidth,u32 srcheight,u32 incx,u32 incy,bitmap_ind8 & priority,u32 pmask,u32 trans_pen)688 void ms32_sprite_device::prio_zoom_transpen(bitmap_rgb32 &dest, const rectangle &cliprect,
689 		u32 code, u32 color, int flipx, int flipy, s32 destx, s32 desty, u32 tx, u32 ty, u32 srcwidth, u32 srcheight,
690 		u32 incx, u32 incy, bitmap_ind8 &priority, u32 pmask,
691 		u32 trans_pen)
692 {
693 	// non-zoom case
694 	if (incx == 0x100 && incy == 0x100)
695 		return prio_transpen(dest, cliprect, code, color, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, priority, pmask, trans_pen);
696 
697 	// special case invalid pens to opaque
698 	if (trans_pen > 0xff)
699 		return prio_zoom_opaque(dest, cliprect, code, color, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, incx, incy, priority, pmask);
700 
701 	// use pen usage to optimize
702 	code %= gfx(0)->elements();
703 	if (gfx(0)->has_pen_usage())
704 	{
705 		// fully transparent; do nothing
706 		u32 usage = gfx(0)->pen_usage(code);
707 		if ((usage & ~(1 << trans_pen)) == 0)
708 			return;
709 
710 		// fully opaque; draw as such
711 		if ((usage & (1 << trans_pen)) == 0)
712 			return prio_zoom_opaque(dest, cliprect, code, color, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, incx, incy, priority, pmask);
713 	}
714 
715 	// high bit of the mask is implicitly on
716 	pmask |= 1 << 31;
717 
718 	// render
719 	const pen_t *paldata = palette().pens() + gfx(0)->colorbase() + gfx(0)->granularity() * (color % gfx(0)->colors());
720 	draw_sprite_zoom_core(dest, cliprect, code, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, incx, incy, priority, [pmask, trans_pen, paldata](u32 &destp, u8 &pri, const u8 &srcp) { PIXEL_OP_REMAP_TRANSPEN_PRIORITY(destp, pri, srcp); });
721 }
722 
723 
724 /*-------------------------------------------------
725     prio_zoom_transpen_raw - render a scaled gfx
726     element with a single transparent pen and no
727     color lookups, checking against the priority
728     bitmap
729 -------------------------------------------------*/
730 
prio_zoom_transpen_raw(bitmap_ind16 & dest,const rectangle & cliprect,u32 code,u32 color,int flipx,int flipy,s32 destx,s32 desty,u32 tx,u32 ty,u32 srcwidth,u32 srcheight,u32 incx,u32 incy,bitmap_ind8 & priority,u32 pmask,u32 trans_pen)731 void ms32_sprite_device::prio_zoom_transpen_raw(bitmap_ind16 &dest, const rectangle &cliprect,
732 		u32 code, u32 color, int flipx, int flipy, s32 destx, s32 desty, u32 tx, u32 ty, u32 srcwidth, u32 srcheight,
733 		u32 incx, u32 incy, bitmap_ind8 &priority, u32 pmask,
734 		u32 trans_pen)
735 {
736 	// non-zoom case
737 	if (incx == 0x100 && incy == 0x100)
738 		return prio_transpen_raw(dest, cliprect, code, color, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, priority, pmask, trans_pen);
739 
740 	// early out if completely transparent
741 	code %= gfx(0)->elements();
742 	if (gfx(0)->has_pen_usage() && (gfx(0)->pen_usage(code) & ~(1 << trans_pen)) == 0)
743 		return;
744 
745 	// high bit of the mask is implicitly on
746 	pmask |= 1 << 31;
747 
748 	// render
749 	draw_sprite_zoom_core(dest, cliprect, code, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, incx, incy, priority, [pmask, trans_pen, color](u16 &destp, u8 &pri, const u8 &srcp) { PIXEL_OP_REBASE_TRANSPEN_PRIORITY(destp, pri, srcp); });
750 }
751 
prio_zoom_transpen_raw(bitmap_rgb32 & dest,const rectangle & cliprect,u32 code,u32 color,int flipx,int flipy,s32 destx,s32 desty,u32 tx,u32 ty,u32 srcwidth,u32 srcheight,u32 incx,u32 incy,bitmap_ind8 & priority,u32 pmask,u32 trans_pen)752 void ms32_sprite_device::prio_zoom_transpen_raw(bitmap_rgb32 &dest, const rectangle &cliprect,
753 		u32 code, u32 color, int flipx, int flipy, s32 destx, s32 desty, u32 tx, u32 ty, u32 srcwidth, u32 srcheight,
754 		u32 incx, u32 incy, bitmap_ind8 &priority, u32 pmask,
755 		u32 trans_pen)
756 {
757 	// non-zoom case
758 	if (incx == 0x100 && incy == 0x100)
759 		return prio_transpen_raw(dest, cliprect, code, color, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, priority, pmask, trans_pen);
760 
761 	// early out if completely transparent
762 	code %= gfx(0)->elements();
763 	if (gfx(0)->has_pen_usage() && (gfx(0)->pen_usage(code) & ~(1 << trans_pen)) == 0)
764 		return;
765 
766 	// high bit of the mask is implicitly on
767 	pmask |= 1 << 31;
768 
769 	// render
770 	draw_sprite_zoom_core(dest, cliprect, code, flipx, flipy, destx, desty, tx, ty, srcwidth, srcheight, incx, incy, priority, [pmask, trans_pen, color](u32 &destp, u8 &pri, const u8 &srcp) { PIXEL_OP_REBASE_TRANSPEN_PRIORITY(destp, pri, srcp); });
771 }
772 
773 /***************************************************************************
774     BASIC DRAWGFX CORE
775 ***************************************************************************/
776 
777 /*
778     Input parameters:
779         bitmap_t &dest - the bitmap to render to
780         const rectangle &cliprect - a clipping rectangle (assumed to be clipped to the size of 'dest')
781         gfx_element *gfx - pointer to the gfx_element to render
782         u32 code - index of the entry within gfx_element
783         int flipx - non-zero means render right-to-left instead of left-to-right
784         int flipy - non-zero means render bottom-to-top instead of top-to-bottom
785         s32 destx - the top-left X coordinate to render to
786         s32 desty - the top-left Y coordinate to render to
787         bitmap_t &priority - the priority bitmap (if and only if priority is to be applied)
788 */
789 
790 
791 template <typename BitmapType, typename FunctionClass>
draw_sprite_core(BitmapType & dest,const rectangle & cliprect,u32 code,int flipx,int flipy,s32 destx,s32 desty,u32 tx,u32 ty,u32 srcwidth,u32 srcheight,FunctionClass pixel_op)792 inline void ms32_sprite_device::draw_sprite_core(BitmapType &dest, const rectangle &cliprect, u32 code, int flipx, int flipy, s32 destx, s32 desty, u32 tx, u32 ty, u32 srcwidth, u32 srcheight, FunctionClass pixel_op)
793 {
794 	g_profiler.start(PROFILER_DRAWGFX);
795 	do {
796 		assert(dest.valid());
797 		assert(dest.cliprect().contains(cliprect));
798 		assert(code < gfx(0)->elements());
799 
800 		// ignore empty/invalid cliprects
801 		if (cliprect.empty())
802 			break;
803 
804 		// compute final pixel in X and exit if we are entirely clipped
805 		s32 destendx = destx + srcwidth - 1;
806 		if (destx > cliprect.right() || destendx < cliprect.left())
807 			break;
808 
809 		// apply left clip
810 		u32 srcx = 0;
811 		if (destx < cliprect.left())
812 		{
813 			srcx = cliprect.left() - destx;
814 			destx = cliprect.left();
815 		}
816 
817 		// apply right clip
818 		if (destendx > cliprect.right())
819 			destendx = cliprect.right();
820 
821 		// compute final pixel in Y and exit if we are entirely clipped
822 		s32 destendy = desty + srcheight - 1;
823 		if (desty > cliprect.bottom() || destendy < cliprect.top())
824 			break;
825 
826 		// apply top clip
827 		u32 srcy = 0;
828 		if (desty < cliprect.top())
829 		{
830 			srcy = cliprect.top() - desty;
831 			desty = cliprect.top();
832 		}
833 
834 		// apply bottom clip
835 		if (destendy > cliprect.bottom())
836 			destendy = cliprect.bottom();
837 
838 		// apply X flipping
839 		s32 dx = 1;
840 		if (flipx)
841 		{
842 			srcx = srcwidth - 1 - srcx;
843 			dx = -dx;
844 		}
845 
846 		// apply Y flipping
847 		s32 dy = 1;
848 		if (flipy)
849 		{
850 			srcy = srcheight - 1 - srcy;
851 			dy = -dy;
852 		}
853 
854 		// fetch the source data
855 		const u8 *srcdata = gfx(0)->get_data(code);
856 
857 		// compute how many blocks of 4 pixels we have
858 		u32 numblocks = (destendx + 1 - destx) / 4;
859 		u32 leftovers = (destendx + 1 - destx) - 4 * numblocks;
860 
861 		// iterate over pixels in Y
862 		for (s32 cury = desty; cury <= destendy; cury++)
863 		{
864 			u32 drawy = ty + srcy;
865 			srcy += dy;
866 			if (drawy >= gfx(0)->height())
867 				continue;
868 
869 			auto *destptr = &dest.pix(cury, destx);
870 			const u8 *srcptr = srcdata + (drawy * gfx(0)->rowbytes());
871 
872 			u32 cursrcx = srcx;
873 			// iterate over unrolled blocks of 4
874 			for (s32 curx = 0; curx < numblocks; curx++)
875 			{
876 				if (tx + cursrcx < gfx(0)->width()) { pixel_op(destptr[0], srcptr[tx + cursrcx]); } cursrcx += dx;
877 				if (tx + cursrcx < gfx(0)->width()) { pixel_op(destptr[1], srcptr[tx + cursrcx]); } cursrcx += dx;
878 				if (tx + cursrcx < gfx(0)->width()) { pixel_op(destptr[2], srcptr[tx + cursrcx]); } cursrcx += dx;
879 				if (tx + cursrcx < gfx(0)->width()) { pixel_op(destptr[3], srcptr[tx + cursrcx]); } cursrcx += dx;
880 
881 				destptr += 4;
882 			}
883 
884 			// iterate over leftover pixels
885 			for (s32 curx = 0; curx < leftovers; curx++)
886 			{
887 				if (tx + cursrcx < gfx(0)->width()) { pixel_op(destptr[0], srcptr[tx + cursrcx]); } cursrcx += dx;
888 				destptr++;
889 			}
890 		}
891 	} while (0);
892 	g_profiler.stop();
893 }
894 
895 
896 template <typename BitmapType, typename PriorityType, typename FunctionClass>
draw_sprite_core(BitmapType & dest,const rectangle & cliprect,u32 code,int flipx,int flipy,s32 destx,s32 desty,u32 tx,u32 ty,u32 srcwidth,u32 srcheight,PriorityType & priority,FunctionClass pixel_op)897 inline void ms32_sprite_device::draw_sprite_core(BitmapType &dest, const rectangle &cliprect, u32 code, int flipx, int flipy, s32 destx, s32 desty, u32 tx, u32 ty, u32 srcwidth, u32 srcheight, PriorityType &priority, FunctionClass pixel_op)
898 {
899 	g_profiler.start(PROFILER_DRAWGFX);
900 	do {
901 		assert(dest.valid());
902 		assert(priority.valid());
903 		assert(dest.cliprect().contains(cliprect));
904 		assert(code < gfx(0)->elements());
905 
906 		// ignore empty/invalid cliprects
907 		if (cliprect.empty())
908 			break;
909 
910 		// compute final pixel in X and exit if we are entirely clipped
911 		s32 destendx = destx + srcwidth - 1;
912 		if (destx > cliprect.right() || destendx < cliprect.left())
913 			break;
914 
915 		// apply left clip
916 		u32 srcx = 0;
917 		if (destx < cliprect.left())
918 		{
919 			srcx = cliprect.left() - destx;
920 			destx = cliprect.left();
921 		}
922 
923 		// apply right clip
924 		if (destendx > cliprect.right())
925 			destendx = cliprect.right();
926 
927 		// compute final pixel in Y and exit if we are entirely clipped
928 		s32 destendy = desty + srcheight - 1;
929 		if (desty > cliprect.bottom() || destendy < cliprect.top())
930 			break;
931 
932 		// apply top clip
933 		u32 srcy = 0;
934 		if (desty < cliprect.top())
935 		{
936 			srcy = cliprect.top() - desty;
937 			desty = cliprect.top();
938 		}
939 
940 		// apply bottom clip
941 		if (destendy > cliprect.bottom())
942 			destendy = cliprect.bottom();
943 
944 		// apply X flipping
945 		s32 dx = 1;
946 		if (flipx)
947 		{
948 			srcx = srcwidth - 1 - srcx;
949 			dx = -dx;
950 		}
951 
952 		// apply Y flipping
953 		s32 dy = 1;
954 		if (flipy)
955 		{
956 			srcy = srcheight - 1 - srcy;
957 			dy = -dy;
958 		}
959 
960 		// fetch the source data
961 		const u8 *srcdata = gfx(0)->get_data(code);
962 
963 		// compute how many blocks of 4 pixels we have
964 		u32 numblocks = (destendx + 1 - destx) / 4;
965 		u32 leftovers = (destendx + 1 - destx) - 4 * numblocks;
966 
967 		// iterate over pixels in Y
968 		for (s32 cury = desty; cury <= destendy; cury++)
969 		{
970 			u32 drawy = ty + srcy;
971 			srcy += dy;
972 			if (drawy >= gfx(0)->height())
973 				continue;
974 
975 			auto *priptr = &priority.pix(cury, destx);
976 			auto *destptr = &dest.pix(cury, destx);
977 			const u8 *srcptr = srcdata + (drawy * gfx(0)->rowbytes());
978 
979 			u32 cursrcx = srcx;
980 			// iterate over unrolled blocks of 4
981 			for (s32 curx = 0; curx < numblocks; curx++)
982 			{
983 				if (tx + cursrcx < gfx(0)->width()) { pixel_op(destptr[0], priptr[0], srcptr[tx + cursrcx]); } cursrcx += dx;
984 				if (tx + cursrcx < gfx(0)->width()) { pixel_op(destptr[1], priptr[1], srcptr[tx + cursrcx]); } cursrcx += dx;
985 				if (tx + cursrcx < gfx(0)->width()) { pixel_op(destptr[2], priptr[2], srcptr[tx + cursrcx]); } cursrcx += dx;
986 				if (tx + cursrcx < gfx(0)->width()) { pixel_op(destptr[3], priptr[3], srcptr[tx + cursrcx]); } cursrcx += dx;
987 
988 				destptr += 4;
989 				priptr += 4;
990 			}
991 
992 			// iterate over leftover pixels
993 			for (s32 curx = 0; curx < leftovers; curx++)
994 			{
995 				if (tx + cursrcx < gfx(0)->width()) { pixel_op(destptr[0], priptr[0], srcptr[tx + cursrcx]); } cursrcx += dx;
996 				destptr++;
997 				priptr++;
998 			}
999 		}
1000 	} while (0);
1001 	g_profiler.stop();
1002 }
1003 /***************************************************************************
1004     BASIC DRAWGFXZOOM CORE
1005 ***************************************************************************/
1006 
1007 /*
1008     Input parameters:
1009         bitmap_t &dest - the bitmap to render to
1010         const rectangle &cliprect - a clipping rectangle (assumed to be clipped to the size of 'dest')
1011         gfx_element *gfx - pointer to the gfx_element to render
1012         u32 code - index of the entry within gfx_element
1013         int flipx - non-zero means render right-to-left instead of left-to-right
1014         int flipy - non-zero means render bottom-to-top instead of top-to-bottom
1015         s32 destx - the top-left X coordinate to render to
1016         s32 desty - the top-left Y coordinate to render to
1017         u32 scalex - the 16.16 scale factor in the X dimension
1018         u32 scaley - the 16.16 scale factor in the Y dimension
1019         bitmap_t &priority - the priority bitmap (if and only if priority is to be applied)
1020 */
1021 
1022 
1023 template <typename BitmapType, typename FunctionClass>
draw_sprite_zoom_core(BitmapType & dest,const rectangle & cliprect,u32 code,int flipx,int flipy,s32 destx,s32 desty,u32 tx,u32 ty,u32 srcwidth,u32 srcheight,u32 incx,u32 incy,FunctionClass pixel_op)1024 inline void ms32_sprite_device::draw_sprite_zoom_core(BitmapType &dest, const rectangle &cliprect, u32 code, int flipx, int flipy, s32 destx, s32 desty, u32 tx, u32 ty, u32 srcwidth, u32 srcheight, u32 incx, u32 incy, FunctionClass pixel_op)
1025 {
1026 	if (!incx || !incy)
1027 		return;
1028 
1029 	g_profiler.start(PROFILER_DRAWGFX);
1030 	do {
1031 		assert(dest.valid());
1032 		assert(dest.cliprect().contains(cliprect));
1033 
1034 		// ignore empty/invalid cliprects
1035 		if (cliprect.empty())
1036 			break;
1037 
1038 		s32 srcstartx = tx << 8;
1039 		s32 srcstarty = ty << 8;
1040 		s32 srcendx = srcwidth << 8;
1041 		s32 srcendy = srcheight << 8;
1042 		// apply left clip
1043 		u32 srcx = 0;
1044 		if (destx < cliprect.left())
1045 		{
1046 			srcx = (cliprect.left() - destx) * incx;
1047 			destx = cliprect.left();
1048 		}
1049 		if (srcx >= srcendx)
1050 			break;
1051 
1052 		// apply top clip
1053 		u32 srcy = 0;
1054 		if (desty < cliprect.top())
1055 		{
1056 			srcy = (cliprect.top() - desty) * incy;
1057 			desty = cliprect.top();
1058 		}
1059 		if (srcy >= srcendy)
1060 			break;
1061 
1062 		// fetch the source data
1063 		const u8 *srcdata = gfx(0)->get_data(code);
1064 
1065 		// iterate over pixels in Y
1066 		for (s32 cury = desty; (cury <= cliprect.bottom()) && (srcy < srcendy); cury++, srcy += incy)
1067 		{
1068 			u32 drawy = (srcstarty + (flipy ? (srcendy - srcy - 1) : srcy)) >> 8;
1069 			if (drawy >= gfx(0)->height())
1070 				continue;
1071 
1072 			auto *destptr = &dest.pix(cury);
1073 			const u8 *srcptr = srcdata + drawy * gfx(0)->rowbytes();
1074 			u32 cursrcx = srcx;
1075 
1076 			// iterate over pixels
1077 			for (s32 curx = destx; (curx <= cliprect.right()) && (cursrcx < srcendx); curx++, cursrcx += incx)
1078 			{
1079 				u32 drawx = (srcstartx + (flipx ? (srcendx - cursrcx - 1) : cursrcx)) >> 8;
1080 				if (drawx >= gfx(0)->width())
1081 					continue;
1082 
1083 				pixel_op(destptr[curx], srcptr[drawx]);
1084 			}
1085 		}
1086 	} while (0);
1087 	g_profiler.stop();
1088 }
1089 
1090 
1091 template <typename BitmapType, typename PriorityType, typename FunctionClass>
draw_sprite_zoom_core(BitmapType & dest,const rectangle & cliprect,u32 code,int flipx,int flipy,s32 destx,s32 desty,u32 tx,u32 ty,u32 srcwidth,u32 srcheight,u32 incx,u32 incy,PriorityType & priority,FunctionClass pixel_op)1092 inline void ms32_sprite_device::draw_sprite_zoom_core(BitmapType &dest, const rectangle &cliprect, u32 code, int flipx, int flipy, s32 destx, s32 desty, u32 tx, u32 ty, u32 srcwidth, u32 srcheight, u32 incx, u32 incy, PriorityType &priority, FunctionClass pixel_op)
1093 {
1094 	if (!incx || !incy)
1095 		return;
1096 
1097 	g_profiler.start(PROFILER_DRAWGFX);
1098 	do {
1099 		assert(dest.valid());
1100 		assert(priority.valid());
1101 		assert(dest.cliprect().contains(cliprect));
1102 
1103 		// ignore empty/invalid cliprects
1104 		if (cliprect.empty())
1105 			break;
1106 
1107 		s32 srcstartx = tx << 8;
1108 		s32 srcstarty = ty << 8;
1109 		s32 srcendx = srcwidth << 8;
1110 		s32 srcendy = srcheight << 8;
1111 		// apply left clip
1112 		u32 srcx = 0;
1113 		if (destx < cliprect.left())
1114 		{
1115 			srcx = (cliprect.left() - destx) * incx;
1116 			destx = cliprect.left();
1117 		}
1118 		if (srcx >= srcendx)
1119 			break;
1120 
1121 		// apply top clip
1122 		u32 srcy = 0;
1123 		if (desty < cliprect.top())
1124 		{
1125 			srcy = (cliprect.top() - desty) * incy;
1126 			desty = cliprect.top();
1127 		}
1128 		if (srcy >= srcendy)
1129 			break;
1130 
1131 		// fetch the source data
1132 		const u8 *srcdata = gfx(0)->get_data(code);
1133 
1134 		// iterate over pixels in Y
1135 		for (s32 cury = desty; (cury <= cliprect.bottom()) && (srcy < srcendy); cury++, srcy += incy)
1136 		{
1137 			u32 drawy = (srcstarty + (flipy ? (srcendy - srcy - 1) : srcy)) >> 8;
1138 			if (drawy >= gfx(0)->height())
1139 				continue;
1140 
1141 			auto *priptr = &priority.pix(cury);
1142 			auto *destptr = &dest.pix(cury);
1143 			const u8 *srcptr = srcdata + drawy * gfx(0)->rowbytes();
1144 			u32 cursrcx = srcx;
1145 
1146 			// iterate over pixels
1147 			for (s32 curx = destx; (curx <= cliprect.right()) && (cursrcx < srcendx); curx++, cursrcx += incx)
1148 			{
1149 				u32 drawx = (srcstartx + (flipx ? (srcendx - cursrcx - 1) : cursrcx)) >> 8;
1150 				if (drawx >= gfx(0)->width())
1151 					continue;
1152 
1153 				pixel_op(destptr[curx], priptr[curx], srcptr[drawx]);
1154 			}
1155 		}
1156 	} while (0);
1157 	g_profiler.stop();
1158 }
1159