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