1 
2 /*********************************************************************
3 
4 	artwork.c
5 
6 	Second generation artwork implementation.
7 
8 	Still to do:
9 		- tinting
10 		- mechanism to disable built-in artwork
11 
12 	Longer term:
13 		- struct mame_layer
14 		  {
15 		  	struct mame_bitmap *bitmap;
16 		  	int rectcount;
17 		  	struct rectangle rectlist[MAX_RECTS];
18 		  }
19 		- add 4 mame_layers for backdrop, overlay, bezel, ui to mame_display
20 		- some mechanism to let the OSD do the blending
21 		- MMX optimized implementations
22 
23 **********************************************************************
24 
25 	This file represents the second attempt at providing external
26 	artwork support. Some parts of this code are based on the
27 	original version, by Mike Balfour and Mathis Rosenhauer.
28 
29 	The goal: to provide artwork support with minimal knowledge of
30 	the game drivers. The previous implementation required the
31 	game drivers to allocate extra pens, extend the screen bitmap,
32 	and handle a lot of the mundane details by hand. This is no
33 	longer the case.
34 
35 	The key to all this is the .art file. A .art file is just a
36 	text file describing all the artwork needed for a particular
37 	game. It lives either in the $ARTWORK/gamename/ directory
38 	or in the $ARTWORK/gamename.zip file, and is called
39 	gamename.art.
40 
41 **********************************************************************
42 
43 	THE ART FILE
44 
45 	The .art file is very simply formatted. It consists of any
46 	number of entries that look like this:
47 
48 	[artname]:
49 		file       = [filename]
50 		alphafile  = [alphafilename]
51 		layer      = [backdrop|overlay|bezel|marquee|panel|side|flyer]
52 		position   = [left],[top],[right],[bottom]
53 		priority   = [priority]
54 		visible    = [visible]
55 		alpha      = [alpha]
56 		brightness = [brightness]
57 
58 	Comments in the .art file follow standard C++ comment format,
59 	starting with a double-slash //. C-style comments are not
60 	recognized.
61 
62 	Fields are:
63 
64 	[artname] - name that is used to reference this piece of
65 		artwork in the game driver. Game drivers can show/hide
66 		pieces of artwork. It is permissible to use the same
67 		name for multiple pieces; in that case, a show/hide
68 		command from the game will affect all pieces with that
69 		name. This field is required.
70 
71 	file - name of the PNG file containing the main artwork.
72 		This file should live in the same directory as the .art
73 		file itself. Most PNG formats are supported. If the
74 		PNG file does not have an alpha channel or transparent
75 		colors, it will be loaded fully opaque. This field is
76 		required.
77 
78 	alphafile - name of a PNG file containing the alpha channel.
79 		Like the main file, this file should live in the same
80 		directory as the .art file. The alphafile must have the
81 		exact same dimensions as the main art file in order to
82 		be valid. When loaded, the brightness of each pixel in
83 		the alphafile controls the alpha channel for the
84 		corresponding pixel in the main art.
85 
86 	layer - classifies this piece of artwork into one of several
87 		predefined categories. Command line options can control
88 		which categories of artwork are actually displayed. The
89 		layer is also used to group the artwork for rendering
90 		(see discussion of rendering below.) This field is
91 		required.
92 
93 	position - specifies the position of this piece of artwork
94 		relative to the game bitmap. See the section on
95 		positioning, below, for the precise details. This field
96 		is required.
97 
98 	priority - specifies the front-to-back ordering of this
99 		piece of art. The various artwork pieces are assembled
100 		from the bottom up, lowest priority to highest priority.
101 		If you want a piece of artwork to appear behind another
102 		piece of artwork, use a lower priority. The default
103 		priority is 0.
104 
105 	visible - sets the initial visible state. By default, all
106 		artwork is visible. The driver code can change this state
107 		at runtime.
108 
109 	alpha - specifies a global, additional alpha value for the
110 		entire piece of artwork. This alpha value is multiplied
111 		by the per-pixel alpha value for the loaded artwork.
112 		The default value is 1.0, which has no net effect on the
113 		loaded alpha. An alpha of 0.0 will make the entire piece
114 		of artwork fully transparent.
115 
116 	brightness - specifies a global brightness adjustment factor
117 		for the entire piece of artwork. The red, green, and blue
118 		components of every pixel are multiplied by this value
119 		when the image is loaded. The default value is 1.0, which
120 		has no net effect on the loaded artwork. A brightness
121 		value of 0.0 will produce an entirely black image.
122 
123 	Once the .art file is loaded, the artwork is categories into
124 	three groups: backdrops, overlays, and everything else. Each
125 	of these groups is handled in its own way.
126 
127 **********************************************************************
128 
129 	BLENDING
130 
131 	Conceptually, here is how it all fits together:
132 
133 	1. A combined backdrop bitmap is assembled. This consists of
134 	taking an opaque black bitmap, and alpha blending all the
135 	backdrop graphics, in order from lowest priority to highest,
136 	into it.
137 
138 	2. A combined overlay bitmap is assembled. This consists of
139 	taking a translucent white overlay and performing a CMY blend
140 	of all the overlay graphics, in order from lowest priority to
141 	highest, into it.
142 
143 	3. A combined bezel bitmap is assembled. This consists of
144 	taking a fully transparent bitmap, and alpha blending all the
145 	bezel, marquee, panel, side, and flyer graphics, in order from
146 	lowest to highest, into it.
147 
148 	4. Depending on the user configurable artwork scale setting,
149 	the game bitmap is potentially expanded 2x.
150 
151 	5. The combined overlay bitmap is applied to the game bitmap,
152 	by using the brightness of the game pixel to control the
153 	brightness of the corresponding overlay bitmap pixel, as
154 	follows:
155 
156 		RGB[mix1] = (RGB[overlay] * A[overlay]) +
157 				(RGB[overlay] - RGB[overlay] * A[overlay]) * Y[game];
158 
159 	where
160 
161 		RGB[mix1] -> RGB components of final mixed bitmap
162 		A[overlay] -> alpha value of combined overlay
163 		RGB[overlay] -> RGB components of combined overlay
164 		Y[game] -> brightness of game pixel
165 
166 	6. The result of the overlay + game blending is then added to
167 	the backdrop, as follows:
168 
169 		RGB[mix2] = RGB[mix1] + RGB[backdrop]
170 
171 	where
172 
173 		RGB[mix2] -> RGB components of final mixed bitmap
174 		RGB[mix1] -> RGB components of game + overlay mixing
175 		RGB[backdrop] -> RGB components of combined backdrop graphics
176 
177 	7. The combined bezel bitmap is alpha blended against the
178 	result of the previous operation, as follows:
179 
180 		RGB[final] = (RGB[mix2] * (1 - A[bezel])) + (RGB[bezel] * A[bezel])
181 
182 	where
183 
184 		RGB[final] -> RGB components of final bitmap
185 		A[bezel] -> alpha value of combined bezel
186 		RGB[bezel] -> RGB components of combined bezel
187 		RGB[mix2] -> RGB components of game + overlay + backdrop mixing
188 
189 **********************************************************************
190 
191 	POSITIONING
192 
193 	The positioning of the artwork is a little tricky.
194 	Conceptually, the game bitmap occupies the space from (0,0)
195 	to (1,1). If you have a piece of artwork that exactly covers
196 	the game area, then it too should stretch from (0,0) to (1,1).
197 	However, most of the time, this is not the case.
198 
199 	For example, if you have, say, the Spy Hunter bezel at the
200 	bottom of the screen, then you will want to specify the top
201 	of the artwork at 1.0 and the bottom at something larger, maybe
202 	1.25. The nice thing about the new artwork system is that it
203 	will automatically stretch the bitmaps out to accomodate areas
204 	beyond the game bitmap, and will still keep the proper aspect
205 	ratio.
206 
207 	Another common example is a backdrop that extends beyond all
208 	four corners of the game bitmap. Here is how you would handle
209 	that, in detail:
210 
211 	Let's say you have some artwork like this:
212 
213 	 <============ 883 pixels ===============>
214 
215 	(1)-------------------------------------(2)  ^
216 	 |                  ^                    |   |
217 	 |              26 pixels                |   |
218 	 |                  v                    |   |
219 	 |     (5)-----------------------(6)     |   |
220 	 |      |                         |      |   |
221 	 |      |                         |      |   |
222 	 |      |                         |      |   |
223 	 |<---->|                         |      |   |
224 	 |  97  |      Game screen        |      |  768
225 	 |pixels|       700 x 500         |      | pixels
226 	 |      |                         |<---->|   |
227 	 |      |                         |  86  |   |
228 	 |      |                         |pixels|   |
229 	 |      |                         |      |   |
230 	 |      |                         |      |   |
231 	 |     (7)-----------------------(8)     |   |
232 	 |                  ^                    |   |
233 	 |              42 pixels                |   |
234 	 |                  v                    |   |
235 	(3)-------------------------------------(4)  v
236 
237 	If you're looking at the raw coordinates as might seem
238 	logical, you would imagine that they come out like this:
239 
240 		(1) is at (0,0)
241 		(2) is at (883,0)
242 		(3) is at (0,768)
243 		(4) is at (883,768)
244 
245 		(5) is at (97,26)
246 		(6) is at (797,26)
247 		(7) is at (97,526)
248 		(8) is at (797,526)
249 
250 	The first thing you need to do is adjust the coordinates
251 	so that the upper left corner of the game screen (point 5)
252 	is at (0,0). To do that, you need to subtract 97 from
253 	each X coordinate and 26 from each Y coordinate:
254 
255 		(1) is at (0-97,0-26)     -> (-97,-26)
256 		(2) is at (883-97,0-26)   -> (786,-26)
257 		(3) is at (0-97,768-26)   -> (-97,742)
258 		(4) is at (883-97,768-26) -> (883,742)
259 
260 		(5) is at (97-97,26-26)   -> (0,0)
261 		(6) is at (797-97,26-26)  -> (700,0)
262 		(7) is at (97-97,526-26)  -> (0,500)
263 		(8) is at (797-97,526-26) -> (700,500)
264 
265 	The final thing you need to do is make it so the bottom
266 	right corner of the image (point 8) is at (1.0,1.0). To do
267 	that, you need to divide each coordinate by the width
268 	or height of the image
269 
270 		(1) is at (-97/700,-26/500)  -> (-0.13857,-0.052)
271 		(2) is at (786/700,-26/500)  -> (1.122857,-0.052)
272 		(3) is at (-97/700,742/500)  -> (-0.13857, 1.484)
273 		(4) is at (883/700,742/500)  -> (1.122857, 1.484)
274 
275 		(5) is at (0/700,0/500)      -> (0.0,0.0)
276 		(6) is at (700/700,0/500)    -> (1.0,0.0)
277 		(7) is at (0/700,500/500)    -> (0.0,1.0)
278 		(8) is at (700/700,500/500)  -> (1.0,1.0)
279 
280 	Alternately, you can also provide pixel coordinates, but it will
281 	still be relative to the game's native resolution. So, if
282 	the game normally runs at 256x224, you'll need to compute
283 	the division factor so that the bottom right corner of the
284 	game (point 8) ends up at (256,224) instead of (1.0,1.0).
285 
286 	Basically, if you have the original coordinates shown
287 	right below the image, you can compute the values needed by
288 	doing this for X coordinates:
289 
290 		(X coordinate on artwork) - (X coordinate of game's upper-left)
291 		---------------------------------------------------------------
292 		           (width of game in artwork pixels)
293 
294 	And this for Y coordinates:
295 
296 		(Y coordinate on artwork) - (Y coordinate of game's upper-left)
297 		---------------------------------------------------------------
298 			       (height of game in artwork pixels)
299 
300 *********************************************************************/
301 
302 
303 #include "driver.h"
304 #include "png.h"
305 #include "artwork.h"
306 #include "vidhrdw/vector.h"
307 #include <ctype.h>
308 #include <math.h>
309 
310 
311 /***************************************************************************
312 
313 	Constants & macros
314 
315 ***************************************************************************/
316 
317 /* maxima */
318 #define MAX_PIECES				1024
319 #define MAX_HINTS_PER_SCANLINE	4
320 
321 /* fixed-point fraction helpers */
322 #define FRAC_BITS				24
323 #define FRAC_ONE				(1 << FRAC_BITS)
324 #define FRAC_MASK				(FRAC_ONE - 1)
325 #define FRAC_HALF				(FRAC_ONE / 2)
326 
327 /* layer types */
328 enum
329 {
330 	LAYER_UNKNOWN,
331 	LAYER_BACKDROP,
332 	LAYER_OVERLAY,
333 	LAYER_BEZEL,
334 	LAYER_MARQUEE,
335 	LAYER_PANEL,
336 	LAYER_SIDE,
337 	LAYER_FLYER
338 };
339 
340 /* UI transparency hack */
341 #define UI_TRANSPARENT_COLOR16	0xfffe
342 #define UI_TRANSPARENT_COLOR32	0xfffffffe
343 
344 /* assemble ARGB components in the platform's preferred format */
345 #define ASSEMBLE_ARGB(a,r,g,b)	(((a) << ashift) | ((r) << rshift) | ((g) << gshift) | ((b) << bshift))
346 
347 
348 
349 /***************************************************************************
350 
351 	Type definitions
352 
353 ***************************************************************************/
354 
355 struct artwork_piece
356 {
357 	/* linkage */
358 	struct artwork_piece *	next;
359 
360 	/* raw data from the .art file */
361 	UINT8					layer;
362 	UINT8					has_alpha;
363 	int					priority;
364 	float					alpha;
365 	float					brightness;
366 	float					top;
367 	float					left;
368 	float					bottom;
369 	float					right;
370 	char *					tag;
371 	char *					filename;
372 	char *					alpha_filename;
373 
374 	/* bitmaps */
375 	struct mame_bitmap *	rawbitmap;
376 	struct mame_bitmap *	prebitmap;
377 	struct mame_bitmap *	yrgbbitmap;
378 	UINT32 *				scanlinehint;
379 	UINT8					blendflags;
380 
381 	/* derived/dynamic data */
382 	int						intersects_game;
383 	int						visible;
384 	struct rectangle		bounds;
385 };
386 
387 
388 
389 /***************************************************************************
390 
391 	Local variables
392 
393 ***************************************************************************/
394 
395 static UINT8 rshift, gshift, bshift, ashift;
396 static UINT32 nonalpha_mask;
397 static UINT32 transparent_color;
398 
399 static struct artwork_piece *artwork_list;
400 static int num_underlays, num_overlays, num_bezels;
401 static int num_pieces;
402 
403 static struct mame_bitmap *underlay, *overlay, *overlay_yrgb, *bezel, *final;
404 static struct rectangle underlay_invalid, overlay_invalid, bezel_invalid;
405 static struct rectangle gamerect, screenrect;
406 static int gamescale;
407 
408 static struct mame_bitmap *uioverlay;
409 static UINT32 *uioverlayhint;
410 static struct rectangle uibounds, last_uibounds;
411 
412 static UINT32 *palette_lookup;
413 
414 static int original_attributes;
415 static UINT8 global_artwork_enable;
416 
417 static const struct overlay_piece *overlay_list;
418 
419 
420 
421 /***************************************************************************
422 
423 	Prototypes
424 
425 ***************************************************************************/
426 
427 static int artwork_prep(void);
428 static int artwork_load(const struct GameDriver *gamename, int width, int height, const struct artwork_callbacks *callbacks);
429 static int compute_rgb_components(int depth, UINT32 rgb_components[3], UINT32 rgb32_components[3]);
430 static int load_bitmap(const char *gamename, struct artwork_piece *piece);
431 static int load_alpha_bitmap(const char *gamename, struct artwork_piece *piece, const struct png_info *original);
432 static int scale_bitmap(struct artwork_piece *piece, int newwidth, int newheight);
433 static void trim_bitmap(struct artwork_piece *piece);
434 static int parse_art_file(mame_file *file);
435 static int validate_pieces(void);
436 static void sort_pieces(void);
437 static void update_palette_lookup(struct mame_display *display);
438 static int update_layers(void);
439 static void render_game_bitmap(struct mame_bitmap *bitmap, const rgb_t *palette, struct mame_display *display);
440 static void render_game_bitmap_underlay(struct mame_bitmap *bitmap, const rgb_t *palette, struct mame_display *display);
441 static void render_game_bitmap_overlay(struct mame_bitmap *bitmap, const rgb_t *palette, struct mame_display *display);
442 static void render_game_bitmap_underlay_overlay(struct mame_bitmap *bitmap, const rgb_t *palette, struct mame_display *display);
443 static void render_ui_overlay(struct mame_bitmap *bitmap, UINT32 *dirty, const rgb_t *palette, struct mame_display *display);
444 static void erase_rect(struct mame_bitmap *bitmap, const struct rectangle *bounds, UINT32 color);
445 static void alpha_blend_intersecting_rect(struct mame_bitmap *dstbitmap, const struct rectangle *dstbounds, struct mame_bitmap *srcbitmap, const struct rectangle *srcbounds, const UINT32 *hintlist);
446 static void add_intersecting_rect(struct mame_bitmap *dstbitmap, const struct rectangle *dstbounds, struct mame_bitmap *srcbitmap, const struct rectangle *srcbounds);
447 static void cmy_blend_intersecting_rect(struct mame_bitmap *dstbitmap, struct mame_bitmap *dstyrgbbitmap, const struct rectangle *dstbounds, struct mame_bitmap *srcbitmap, struct mame_bitmap *srcyrgbbitmap, const struct rectangle *srcbounds, UINT8 blendflags);
448 static int generate_overlay(const struct overlay_piece *list, int width, int height);
449 static void add_range_to_hint(UINT32 *hintbase, int scanline, int startx, int endx);
450 
451 
452 
453 #if 0
454 #pragma mark INLINES
455 #endif
456 
457 /*-------------------------------------------------
458 	union_rect - compute the union of two rects
459 -------------------------------------------------*/
460 
union_rect(struct rectangle * dst,const struct rectangle * src)461 static INLINE void union_rect(struct rectangle *dst, const struct rectangle *src)
462 {
463 	if (dst->max_x == 0)
464 		*dst = *src;
465 	else if (src->max_x != 0)
466 	{
467 		dst->min_x = (src->min_x < dst->min_x) ? src->min_x : dst->min_x;
468 		dst->max_x = (src->max_x > dst->max_x) ? src->max_x : dst->max_x;
469 		dst->min_y = (src->min_y < dst->min_y) ? src->min_y : dst->min_y;
470 		dst->max_y = (src->max_y > dst->max_y) ? src->max_y : dst->max_y;
471 	}
472 }
473 
474 
475 
476 /*-------------------------------------------------
477 	compute_brightness - compute the effective
478 	brightness for an RGB pixel
479 -------------------------------------------------*/
480 
compute_brightness(rgb_t rgb)481 static INLINE UINT8 compute_brightness(rgb_t rgb)
482 {
483 	return (RGB_RED(rgb) * 222 + RGB_GREEN(rgb) * 707 + RGB_BLUE(rgb) * 71) / 1000;
484 }
485 
486 
487 
488 /*-------------------------------------------------
489 	compute_pre_pixel - compute a premultiplied
490 	pixel
491 -------------------------------------------------*/
492 
compute_pre_pixel(UINT8 a,UINT8 r,UINT8 g,UINT8 b)493 static INLINE UINT32 compute_pre_pixel(UINT8 a, UINT8 r, UINT8 g, UINT8 b)
494 {
495 	/* premultiply the RGB components with the pixel's alpha */
496 	r = (r * a) / 0xff;
497 	g = (g * a) / 0xff;
498 	b = (b * a) / 0xff;
499 
500 	/* compute the inverted alpha */
501 	a = 0xff - a;
502 	return ASSEMBLE_ARGB(a,r,g,b);
503 }
504 
505 
506 
507 /*-------------------------------------------------
508 	compute_yrgb_pixel - compute a YRGB pixel
509 -------------------------------------------------*/
510 
compute_yrgb_pixel(UINT8 a,UINT8 r,UINT8 g,UINT8 b)511 static INLINE UINT32 compute_yrgb_pixel(UINT8 a, UINT8 r, UINT8 g, UINT8 b)
512 {
513 	/* compute the premultiplied brightness */
514 	int bright = (r * 222 + g * 707 + b * 71) / 1000;
515 	bright = (bright * a) >> 8;
516 
517 	/* now assemble */
518 	return MAKE_ARGB(bright,r,g,b);
519 }
520 
521 
522 
523 /*-------------------------------------------------
524 	add_and_clamp - add two pixels and clamp
525 	each component to the max
526 -------------------------------------------------*/
527 
add_and_clamp(UINT32 game,UINT32 underpix)528 static INLINE UINT32 add_and_clamp(UINT32 game, UINT32 underpix)
529 {
530 	UINT32 temp1 = game + underpix;
531 	UINT32 temp2 = game ^ underpix ^ temp1;
532 
533 	/* handle overflow (carry out of top component */
534 	if (temp1 < game)
535 		temp1 |= 0xff000000;
536 
537 	/* handle carry out of next component */
538 	if (temp2 & 0x01000000)
539 	{
540 		temp1 -= 0x01000000;
541 		temp1 |= 0x00ff0000;
542 	}
543 
544 	/* handle carry out of next component */
545 	if (temp2 & 0x00010000)
546 	{
547 		temp1 -= 0x00010000;
548 		temp1 |= 0x0000ff00;
549 	}
550 
551 	/* handle carry out of final component */
552 	if (temp2 & 0x00000100)
553 	{
554 		temp1 -= 0x00000100;
555 		temp1 |= 0x000000ff;
556 	}
557 	return temp1;
558 }
559 
560 
561 
562 /*-------------------------------------------------
563 	blend_over - blend two pixels with overlay
564 -------------------------------------------------*/
565 
blend_over(UINT32 game,UINT32 pre,UINT32 yrgb)566 static INLINE UINT32 blend_over(UINT32 game, UINT32 pre, UINT32 yrgb)
567 {
568 	/* case 1: no game pixels; just return the premultiplied pixel */
569 	if ((game & nonalpha_mask) == 0)
570 		return pre;
571 
572 	/* case 2: apply the effect */
573 	else
574 	{
575 		UINT8 bright = RGB_GREEN(game);
576 		UINT8 r, g, b;
577 
578 		yrgb -= pre;
579 		r = (RGB_RED(yrgb) * bright) / 256;
580 		g = (RGB_GREEN(yrgb) * bright) / 256;
581 		b = (RGB_BLUE(yrgb) * bright) / 256;
582 		return pre + ASSEMBLE_ARGB(0,r,g,b);
583 	}
584 }
585 
586 
587 
588 #if 0
589 #pragma mark -
590 #pragma mark OSD FRONTENDS
591 #endif
592 
593 /*-------------------------------------------------
594 	artwork_create_display - tweak the display
595 	parameters based on artwork, and call through
596 	to osd_create_display
597 -------------------------------------------------*/
598 
artwork_create_display(struct osd_create_params * params,UINT32 * rgb_components,const struct artwork_callbacks * callbacks)599 int artwork_create_display(struct osd_create_params *params, UINT32 *rgb_components, const struct artwork_callbacks *callbacks)
600 {
601 	int original_width = params->width;
602 	int original_height = params->height;
603 	int original_depth = params->depth;
604 	double min_x, min_y, max_x, max_y;
605 	UINT32 rgb32_components[3];
606 	struct artwork_piece *piece;
607 
608 	/* reset UI */
609 	uioverlay = NULL;
610 	uioverlayhint = NULL;
611 
612 	/* first load the artwork; if none, quit now */
613 	artwork_list = NULL;
614 	if (!artwork_load(Machine->gamedrv, original_width, original_height, callbacks))
615 		return 1;
616 	if (!artwork_list && (!callbacks->activate_artwork || !callbacks->activate_artwork(params)))
617 		return osd_create_display(params, rgb_components);
618 
619 	/* determine the game bitmap scale factor */
620 	gamescale = options.artwork_res;
621 	if (gamescale < 1 || (params->video_attributes & VIDEO_TYPE_VECTOR))
622 		gamescale = 1;
623 
624 	/* compute the extent of all the artwork */
625 	min_x = min_y = 0.0;
626 	max_x = max_y = 1.0;
627 	if (!options.artwork_crop)
628 		for (piece = artwork_list; piece; piece = piece->next)
629 		{
630 			/* compute the outermost bounds */
631 			if (piece->left < min_x) min_x = piece->left;
632 			if (piece->right > max_x) max_x = piece->right;
633 			if (piece->top < min_y) min_y = piece->top;
634 			if (piece->bottom > max_y) max_y = piece->bottom;
635 		}
636 
637 	/* now compute the altered width/height and the new aspect ratio */
638 	params->width = (int)((max_x - min_x) * (double)(original_width * gamescale) + 0.5);
639 	params->height = (int)((max_y - min_y) * (double)(original_height * gamescale) + 0.5);
640 	params->aspect_x = (int)((double)params->aspect_x * 100. * (max_x - min_x));
641 	params->aspect_y = (int)((double)params->aspect_y * 100. * (max_y - min_y));
642 
643 	/* vector games need to fit inside the original bounds, so scale back down */
644 	if (params->video_attributes & VIDEO_TYPE_VECTOR)
645 	{
646 		/* shrink the width/height if over */
647 		if (params->width > original_width)
648 		{
649 			params->width = original_width;
650 			params->height = original_width * params->aspect_y / params->aspect_x;
651 		}
652 		if (params->height > original_height)
653 		{
654 			params->height = original_height;
655 			params->width = original_height * params->aspect_x / params->aspect_y;
656 		}
657 
658 		/* compute the new raw width/height and update the vector info */
659 		original_width = (int)((double)params->width / (max_x - min_x));
660 		original_height = (int)((double)params->height / (max_y - min_y));
661 		options.vector_width = original_width;
662 		options.vector_height = original_height;
663 	}
664 
665 	/* adjust the parameters */
666 	original_attributes = params->video_attributes;
667 	params->video_attributes |= VIDEO_RGB_DIRECT | VIDEO_NEEDS_6BITS_PER_GUN;
668 	params->depth = 32;
669 
670 	/* allocate memory for the bitmaps */
671 	underlay = auto_bitmap_alloc_depth(params->width, params->height, 32);
672 	overlay = auto_bitmap_alloc_depth(params->width, params->height, 32);
673 	overlay_yrgb = auto_bitmap_alloc_depth(params->width, params->height, 32);
674 	bezel = auto_bitmap_alloc_depth(params->width, params->height, 32);
675 	final = auto_bitmap_alloc_depth(params->width, params->height, 32);
676 	if (!final || !overlay || !overlay_yrgb || !underlay || !bezel)
677 		return 1;
678 
679 	/* allocate the UI overlay */
680 	uioverlay = auto_bitmap_alloc_depth(params->width, params->height, Machine->color_depth);
681 	if (uioverlay)
682 		uioverlayhint = auto_malloc(uioverlay->height * MAX_HINTS_PER_SCANLINE * sizeof(uioverlayhint[0]));
683 	if (!uioverlay || !uioverlayhint)
684 		return 1;
685 	fillbitmap(uioverlay, (Machine->color_depth == 32) ? UI_TRANSPARENT_COLOR32 : UI_TRANSPARENT_COLOR16, NULL);
686 	memset(uioverlayhint, 0, uioverlay->height * MAX_HINTS_PER_SCANLINE * sizeof(uioverlayhint[0]));
687 
688 	/* compute the screen rect */
689 	screenrect.min_x = screenrect.min_y = 0;
690 	screenrect.max_x = params->width - 1;
691 	screenrect.max_y = params->height - 1;
692 
693 	/* compute the game rect */
694 	gamerect.min_x = (int)(-min_x * (double)(original_width * gamescale) + 0.5);
695 	gamerect.min_y = (int)(-min_y * (double)(original_height * gamescale) + 0.5);
696 	gamerect.max_x = gamerect.min_x + original_width * gamescale - 1;
697 	gamerect.max_y = gamerect.min_y + original_height * gamescale - 1;
698 
699 	/* now try to create the display */
700 	if (osd_create_display(params, rgb32_components))
701 		return 1;
702 
703 	/* fill in our own RGB components */
704 	if (compute_rgb_components(original_depth, rgb_components, rgb32_components))
705 	{
706 		osd_close_display();
707 		return 1;
708 	}
709 
710 	/* now compute all the artwork pieces' coordinates */
711 	for (piece = artwork_list; piece; piece = piece->next)
712 	{
713 		piece->bounds.min_x = (int)((piece->left - min_x) * (double)(original_width * gamescale) + 0.5);
714 		piece->bounds.min_y = (int)((piece->top - min_y) * (double)(original_height * gamescale) + 0.5);
715 		piece->bounds.max_x = (int)((piece->right - min_x) * (double)(original_width * gamescale) + 0.5) - 1;
716 		piece->bounds.max_y = (int)((piece->bottom - min_y) * (double)(original_height * gamescale) + 0.5) - 1;
717 	}
718 
719 	/* now do the final prep on the artwork */
720 	return artwork_prep();
721 }
722 
723 
724 /*-------------------------------------------------
725 	artwork_system_active - checks to see if the
726 	artwork system is currently active
727 -------------------------------------------------*/
728 
artwork_system_active(void)729 static int artwork_system_active(void)
730 {
731 	return artwork_list || uioverlay;
732 }
733 
734 
735 /*-------------------------------------------------
736 	artwork_update_visible_area - resize artwork
737 	when the game changes resolution
738 -------------------------------------------------*/
739 
artwork_update_visible_area(struct mame_display * display)740 void artwork_update_visible_area(struct mame_display *display)
741 {
742 	double min_x, min_y, max_x, max_y;
743 	int width, height;
744 	int original_width = ( display->game_visible_area.max_x - display->game_visible_area.min_x ) + 1;
745 	int original_height = ( display->game_visible_area.max_y - display->game_visible_area.min_y ) + 1;
746 
747 	struct artwork_piece *piece;
748 	/* compute the extent of all the artwork */
749 	min_x = min_y = 0.0;
750 	max_x = max_y = 1.0;
751 	if (!options.artwork_crop)
752 		for (piece = artwork_list; piece; piece = piece->next)
753 		{
754 			/* compute the outermost bounds */
755 			if (piece->left < min_x) min_x = piece->left;
756 			if (piece->right > max_x) max_x = piece->right;
757 			if (piece->top < min_y) min_y = piece->top;
758 			if (piece->bottom > max_y) max_y = piece->bottom;
759 		}
760 
761 	width = (int)((max_x - min_x) * (double)(original_width * gamescale) + 0.5);
762 	height = (int)((max_y - min_y) * (double)(original_height * gamescale) + 0.5);
763 
764 	/* compute the screen rect */
765 	screenrect.min_x = screenrect.min_y = 0;
766 	screenrect.max_x = width - 1;
767 	screenrect.max_y = height - 1;
768 
769 	/* compute the game rect */
770 	gamerect.min_x = (int)(-min_x * (double)(original_width * gamescale) + 0.5);
771 	gamerect.min_y = (int)(-min_y * (double)(original_height * gamescale) + 0.5);
772 	gamerect.max_x = gamerect.min_x + original_width * gamescale - 1;
773 	gamerect.max_y = gamerect.min_y + original_height * gamescale - 1;
774 
775 	/* now compute all the artwork pieces' coordinates */
776 	for (piece = artwork_list; piece; piece = piece->next)
777 	{
778 		piece->bounds.min_x = (int)((piece->left - min_x) * (double)(original_width * gamescale) + 0.5);
779 		piece->bounds.min_y = (int)((piece->top - min_y) * (double)(original_height * gamescale) + 0.5);
780 		piece->bounds.max_x = (int)((piece->right - min_x) * (double)(original_width * gamescale) + 0.5) - 1;
781 		piece->bounds.max_y = (int)((piece->bottom - min_y) * (double)(original_height * gamescale) + 0.5) - 1;
782 	}
783 
784 
785 
786 	artwork_prep();
787 }
788 
789 
790 
791 
792 
793 
794 /*-------------------------------------------------
795 	artwork_update_video_and_audio - update the
796 	screen, adjusting for artwork
797 -------------------------------------------------*/
798 
artwork_update_video_and_audio(struct mame_display * display)799 void artwork_update_video_and_audio(struct mame_display *display)
800 {
801 	static struct rectangle ui_changed_bounds;
802 	static int ui_changed;
803 	int artwork_changed = 0, ui_visible = 0;
804 
805 	/* do nothing if no artwork */
806 	if (!artwork_system_active())
807 	{
808 		osd_update_video_and_audio(display);
809 		return;
810 	}
811 
812 	profiler_mark(PROFILER_ARTWORK);
813 
814 	/* if the visible area has changed, update it */
815 	if (display->changed_flags & GAME_VISIBLE_AREA_CHANGED)
816 		artwork_update_visible_area(display);
817 
818 
819 	/* update the palette */
820 	if (display->changed_flags & GAME_PALETTE_CHANGED)
821 		update_palette_lookup(display);
822 
823 	/* process the artwork and UI only if we're not frameskipping */
824 	if (display->changed_flags & GAME_BITMAP_CHANGED)
825 	{
826 		/* see if there's any UI to display this frame */
827 		ui_visible = (uibounds.max_x != 0);
828 
829 		/* if the UI bounds changed, refresh everything */
830 		if (last_uibounds.min_x != uibounds.min_x || last_uibounds.min_y != uibounds.min_y ||
831 			last_uibounds.max_x != uibounds.max_x || last_uibounds.max_y != uibounds.max_y)
832 		{
833 			/* compute the union of the two rects */
834 			ui_changed_bounds = last_uibounds;
835 			union_rect(&ui_changed_bounds, &uibounds);
836 			last_uibounds = uibounds;
837 
838 			/* track changes for a few frames */
839 			ui_changed = 3;
840 		}
841 
842 		/* if we have changed pending, mark the artwork dirty */
843 		if (ui_changed)
844 		{
845 			union_rect(&underlay_invalid, &ui_changed_bounds);
846 			union_rect(&overlay_invalid, &ui_changed_bounds);
847 			union_rect(&bezel_invalid, &ui_changed_bounds);
848 			ui_changed--;
849 		}
850 
851 		/* artwork disabled case */
852 		if (!global_artwork_enable)
853 		{
854 			fillbitmap(final, MAKE_ARGB(0,0,0,0), NULL);
855 			union_rect(&underlay_invalid, &screenrect);
856 			union_rect(&overlay_invalid, &screenrect);
857 			union_rect(&bezel_invalid, &screenrect);
858 			render_game_bitmap(display->game_bitmap, palette_lookup, display);
859 		}
860 
861 		/* artwork enabled */
862 		else
863 		{
864 			/* update the underlay and overlay */
865 			artwork_changed = update_layers();
866 
867 			/* render to the final bitmap */
868 			if (num_underlays && num_overlays)
869 				render_game_bitmap_underlay_overlay(display->game_bitmap, palette_lookup, display);
870 			else if (num_underlays)
871 				render_game_bitmap_underlay(display->game_bitmap, palette_lookup, display);
872 			else if (num_overlays)
873 				render_game_bitmap_overlay(display->game_bitmap, palette_lookup, display);
874 			else
875 				render_game_bitmap(display->game_bitmap, palette_lookup, display);
876 
877 			/* apply the bezel */
878 			if (num_bezels)
879 			{
880 				struct artwork_piece *piece;
881 				for (piece = artwork_list; piece; piece = piece->next)
882 					if (piece->layer >= LAYER_BEZEL && piece->intersects_game)
883 						alpha_blend_intersecting_rect(final, &gamerect, piece->prebitmap, &piece->bounds, piece->scanlinehint);
884 			}
885 		}
886 
887 		/* add UI */
888 		if (ui_visible)
889 			render_ui_overlay(uioverlay, uioverlayhint, palette_lookup, display);
890 
891 		/* if artwork changed, or there's UI, we can't use dirty pixels */
892 		if (artwork_changed || ui_changed || ui_visible)
893 		{
894 			display->changed_flags &= ~VECTOR_PIXELS_CHANGED;
895 			display->vector_dirty_pixels = NULL;
896 		}
897 	}
898 	profiler_mark(PROFILER_END);
899 
900 	/* blit the union of the game/screen rect and the UI bounds */
901 	display->game_bitmap_update = (artwork_changed || ui_changed) ? screenrect : gamerect;
902 	union_rect(&display->game_bitmap_update, &uibounds);
903 
904 	/* force the visible area constant */
905 	display->game_visible_area = screenrect;
906 	display->game_bitmap = final;
907 	osd_update_video_and_audio(display);
908 
909 	/* reset the UI bounds (but only if we rendered the UI) */
910 	if (display->changed_flags & GAME_BITMAP_CHANGED)
911 		uibounds.max_x = 0;
912 }
913 
914 
915 
916 /*-------------------------------------------------
917 	artwork_override_screenshot_params - override
918 	certain parameters when saving a screenshot
919 -------------------------------------------------*/
920 
artwork_override_screenshot_params(struct mame_bitmap ** bitmap,struct rectangle * rect,UINT32 * rgb_components)921 void artwork_override_screenshot_params(struct mame_bitmap **bitmap, struct rectangle *rect, UINT32 *rgb_components)
922 {
923 	if ((*bitmap == Machine->scrbitmap || *bitmap == uioverlay) && artwork_system_active())
924 	{
925 		*rect = screenrect;
926 
927 		/* snapshots require correct direct_rgb_components */
928 		rgb_components[0] = 0xff << rshift;
929 		rgb_components[1] = 0xff << gshift;
930 		rgb_components[2] = 0xff << bshift;
931 		*bitmap = final;
932 	}
933 }
934 
935 
936 
937 /*-------------------------------------------------
938 	artwork_get_ui_bitmap - get the UI bitmap
939 -------------------------------------------------*/
940 
artwork_get_ui_bitmap(void)941 struct mame_bitmap *artwork_get_ui_bitmap(void)
942 {
943 	return uioverlay ? uioverlay : Machine->scrbitmap;
944 }
945 
946 
947 
948 /*-------------------------------------------------
949 	artwork_mark_ui_dirty - mark a portion of the
950 	UI bitmap dirty
951 -------------------------------------------------*/
952 
artwork_mark_ui_dirty(int minx,int miny,int maxx,int maxy)953 void artwork_mark_ui_dirty(int minx, int miny, int maxx, int maxy)
954 {
955 	/* add to the UI overlay hint if it exists */
956 	if (uioverlayhint)
957 	{
958 		struct rectangle rect;
959 		int y;
960 
961 		/* clip to visible */
962 		if (minx < 0)
963 			minx = 0;
964 		if (maxx >= uioverlay->width)
965 			maxx = uioverlay->width - 1;
966 		if (miny < 0)
967 			miny = 0;
968 		if (maxy >= uioverlay->height)
969 			maxy = uioverlay->height - 1;
970 
971 		/* update the global rect */
972 		rect.min_x = minx;
973 		rect.max_x = maxx;
974 		rect.min_y = miny;
975 		rect.max_y = maxy;
976 		union_rect(&uibounds, &rect);
977 
978 		/* add hints for each scanline */
979 		if (minx <= maxx)
980 			for (y = miny; y <= maxy; y++)
981 				add_range_to_hint(uioverlayhint, y, minx, maxx);
982 	}
983 }
984 
985 
986 
987 /*-------------------------------------------------
988 	artwork_get_screensize - get the real screen
989 	size
990 -------------------------------------------------*/
991 
artwork_get_screensize(int * width,int * height)992 void artwork_get_screensize(int *width, int *height)
993 {
994 	if (artwork_list)
995 	{
996 		*width = screenrect.max_x - screenrect.min_x + 1;
997 		*height = screenrect.max_y - screenrect.min_y + 1;
998 	}
999 	else
1000 	{
1001 		*width = Machine->drv->screen_width;
1002 		*height = Machine->drv->screen_height;
1003 	}
1004 }
1005 
1006 
1007 
1008 /*-------------------------------------------------
1009 	artwork_enable - globally enable/disable
1010 	artwork
1011 -------------------------------------------------*/
1012 
artwork_enable(int enable)1013 void artwork_enable(int enable)
1014 {
1015 	global_artwork_enable = enable;
1016 }
1017 
1018 
1019 
1020 /*-------------------------------------------------
1021 	artwork_set_overlay - set the hard-coded
1022 	overlay for this game
1023 -------------------------------------------------*/
1024 
artwork_set_overlay(const struct overlay_piece * overlist)1025 void artwork_set_overlay(const struct overlay_piece *overlist)
1026 {
1027 	overlay_list = overlist;
1028 }
1029 
1030 
1031 
1032 /*-------------------------------------------------
1033 	artwork_show - show/hide a tagged piece of art
1034 -------------------------------------------------*/
1035 
artwork_show(const char * tag,int show)1036 void artwork_show(const char *tag, int show)
1037 {
1038 	struct artwork_piece *piece;
1039 
1040 	/* find all the pieces that match the tag */
1041 	for (piece = artwork_list; piece; piece = piece->next)
1042 		if (piece->tag && !strcmp(piece->tag, tag))
1043 		{
1044 			/* if the state is changing, invalidate that area */
1045 			if (piece->visible != show)
1046 			{
1047 				piece->visible = show;
1048 
1049 				/* backdrop */
1050 				if (piece->layer == LAYER_BACKDROP)
1051 					union_rect(&underlay_invalid, &piece->bounds);
1052 
1053 				/* overlay */
1054 				else if (piece->layer == LAYER_OVERLAY)
1055 					union_rect(&overlay_invalid, &piece->bounds);
1056 
1057 				/* bezel */
1058 				else if (piece->layer >= LAYER_BEZEL)
1059 					union_rect(&bezel_invalid, &piece->bounds);
1060 			}
1061 		}
1062 }
1063 
1064 
1065 
1066 #if 0
1067 #pragma mark -
1068 #pragma mark LAYER PROCESSING
1069 #endif
1070 
1071 /*-------------------------------------------------
1072 	update_layers - update any dirty areas of
1073 	the layers
1074 -------------------------------------------------*/
1075 
update_layers(void)1076 static int update_layers(void)
1077 {
1078 	struct artwork_piece *piece = artwork_list;
1079 	struct rectangle combined;
1080 	int changed = 0;
1081 
1082 	/* update the underlays */
1083 	if (underlay_invalid.max_x != 0)
1084 	{
1085 		sect_rect(&underlay_invalid, &screenrect);
1086 		erase_rect(underlay, &underlay_invalid, 0);
1087 		for (piece = artwork_list; piece; piece = piece->next)
1088 			if (piece->layer == LAYER_BACKDROP && piece->visible && piece->prebitmap)
1089 				alpha_blend_intersecting_rect(underlay, &underlay_invalid, piece->prebitmap, &piece->bounds, piece->scanlinehint);
1090 	}
1091 
1092 	/* update the overlays */
1093 	if (overlay_invalid.max_x != 0)
1094 	{
1095 		sect_rect(&overlay_invalid, &screenrect);
1096 		erase_rect(overlay, &overlay_invalid, transparent_color);
1097 		erase_rect(overlay_yrgb, &overlay_invalid, ASSEMBLE_ARGB(0,0xff,0xff,0xff));
1098 		for (piece = artwork_list; piece; piece = piece->next)
1099 			if (piece->layer == LAYER_OVERLAY && piece->visible && piece->prebitmap)
1100 				cmy_blend_intersecting_rect(overlay, overlay_yrgb, &overlay_invalid, piece->prebitmap, piece->yrgbbitmap, &piece->bounds, piece->blendflags);
1101 	}
1102 
1103 	/* update the bezels */
1104 	if (bezel_invalid.max_x != 0)
1105 	{
1106 		sect_rect(&bezel_invalid, &screenrect);
1107 		erase_rect(bezel, &bezel_invalid, transparent_color);
1108 		for (piece = artwork_list; piece; piece = piece->next)
1109 			if (piece->layer >= LAYER_BEZEL && piece->visible && piece->prebitmap)
1110 				alpha_blend_intersecting_rect(bezel, &bezel_invalid, piece->prebitmap, &piece->bounds, piece->scanlinehint);
1111 	}
1112 
1113 	/* combine the invalid rects */
1114 	combined = underlay_invalid;
1115 	union_rect(&combined, &overlay_invalid);
1116 	union_rect(&combined, &bezel_invalid);
1117 	if (combined.max_x != 0)
1118 	{
1119 		/* blend into the final bitmap */
1120 		erase_rect(final, &combined, 0);
1121 		alpha_blend_intersecting_rect(final, &combined, underlay, &screenrect, NULL);
1122 		add_intersecting_rect(final, &combined, overlay, &screenrect);
1123 		alpha_blend_intersecting_rect(final, &combined, bezel, &screenrect, NULL);
1124 		changed = 1;
1125 	}
1126 
1127 	/* reset the invalid rects */
1128 	underlay_invalid.max_x = 0;
1129 	overlay_invalid.max_x = 0;
1130 	bezel_invalid.max_x = 0;
1131 	return changed;
1132 }
1133 
1134 
1135 
1136 /*-------------------------------------------------
1137 	erase_rect - erase the given bounds of a 32bpp
1138 	bitmap
1139 -------------------------------------------------*/
1140 
erase_rect(struct mame_bitmap * bitmap,const struct rectangle * bounds,UINT32 color)1141 static void erase_rect(struct mame_bitmap *bitmap, const struct rectangle *bounds, UINT32 color)
1142 {
1143 	int x, y;
1144 
1145 	/* loop over rows */
1146 	for (y = bounds->min_y; y <= bounds->max_y; y++)
1147 	{
1148 		UINT32 *dest = (UINT32 *)bitmap->base + y * bitmap->rowpixels;
1149 		for (x = bounds->min_x; x <= bounds->max_x; x++)
1150 			dest[x] = color;
1151 	}
1152 }
1153 
1154 
1155 
1156 /*-------------------------------------------------
1157 	alpha_blend_intersecting_rect - alpha blend an
1158 	artwork piece into a bitmap
1159 -------------------------------------------------*/
1160 
alpha_blend_intersecting_rect(struct mame_bitmap * dstbitmap,const struct rectangle * dstbounds,struct mame_bitmap * srcbitmap,const struct rectangle * srcbounds,const UINT32 * hintlist)1161 static void alpha_blend_intersecting_rect(struct mame_bitmap *dstbitmap, const struct rectangle *dstbounds, struct mame_bitmap *srcbitmap, const struct rectangle *srcbounds, const UINT32 *hintlist)
1162 {
1163 	struct rectangle sect = *srcbounds;
1164 	UINT32 dummy_range[2];
1165 	int lclip, rclip;
1166 	int x, y, h;
1167 
1168 	/* compute the intersection */
1169 	sect_rect(&sect, dstbounds);
1170 
1171 	/* compute the source-relative left/right clip */
1172 	lclip = sect.min_x - srcbounds->min_x;
1173 	rclip = sect.max_x - srcbounds->min_x;
1174 
1175 	/* set up a dummy range */
1176 	dummy_range[0] = srcbitmap->width - 1;
1177 	dummy_range[1] = 0;
1178 
1179 	/* adjust the hintlist for the starting offset */
1180 	if (hintlist)
1181 		hintlist -= srcbounds->min_y * MAX_HINTS_PER_SCANLINE;
1182 
1183 	/* loop over rows */
1184 	for (y = sect.min_y; y <= sect.max_y; y++)
1185 	{
1186 		UINT32 *src = (UINT32 *)srcbitmap->base + (y - srcbounds->min_y) * srcbitmap->rowpixels;
1187 		UINT32 *dest = (UINT32 *)dstbitmap->base + y * dstbitmap->rowpixels + srcbounds->min_x;
1188 		const UINT32 *hint = hintlist ? &hintlist[y * MAX_HINTS_PER_SCANLINE] : &dummy_range[0];
1189 
1190 		/* loop over hints */
1191 		for (h = 0; h < MAX_HINTS_PER_SCANLINE && hint[h] != 0; h++)
1192 		{
1193 			int start = hint[h] >> 16;
1194 			int stop = hint[h] & 0xffff;
1195 
1196 			/* clip to the sect rect */
1197 			if (start < lclip)
1198 				start = lclip;
1199 			else if (start > rclip)
1200 				continue;
1201 			if (stop > rclip)
1202 				stop = rclip;
1203 			else if (stop < lclip)
1204 				continue;
1205 
1206 			/* loop over columns */
1207 			for (x = start; x <= stop; x++)
1208 			{
1209 				/* we don't bother optimizing for transparent here because we hope that the */
1210 				/* hints have removed most of the need */
1211 				UINT32 pix = src[x];
1212 				UINT32 dpix = dest[x];
1213 				int alpha = (pix >> ashift) & 0xff;
1214 
1215 				/* alpha is inverted, so alpha 0 means fully opaque */
1216 				if (alpha == 0)
1217 					dest[x] = pix;
1218 
1219 				/* otherwise, we do a proper blend */
1220 				else
1221 				{
1222 					int r = ((pix >> rshift) & 0xff) + ((alpha * ((dpix >> rshift) & 0xff)) >> 8);
1223 					int g = ((pix >> gshift) & 0xff) + ((alpha * ((dpix >> gshift) & 0xff)) >> 8);
1224 					int b = ((pix >> bshift) & 0xff) + ((alpha * ((dpix >> bshift) & 0xff)) >> 8);
1225 
1226 					/* add the alpha values in inverted space (looks weird but is correct) */
1227 					int a = alpha + ((dpix >> ashift) & 0xff) - 0xff;
1228 					if (a < 0) a = 0;
1229 					dest[x] = ASSEMBLE_ARGB(a,r,g,b);
1230 				}
1231 			}
1232 		}
1233 	}
1234 }
1235 
1236 
1237 
1238 /*-------------------------------------------------
1239 	add_intersecting_rect - add a
1240 	artwork piece into a bitmap
1241 -------------------------------------------------*/
1242 
add_intersecting_rect(struct mame_bitmap * dstbitmap,const struct rectangle * dstbounds,struct mame_bitmap * srcbitmap,const struct rectangle * srcbounds)1243 static void add_intersecting_rect(struct mame_bitmap *dstbitmap, const struct rectangle *dstbounds, struct mame_bitmap *srcbitmap, const struct rectangle *srcbounds)
1244 {
1245 	struct rectangle sect = *srcbounds;
1246 	int x, y, width;
1247 
1248 	/* compute the intersection and resulting width */
1249 	sect_rect(&sect, dstbounds);
1250 	width = sect.max_x - sect.min_x + 1;
1251 
1252 	/* loop over rows */
1253 	for (y = sect.min_y; y <= sect.max_y; y++)
1254 	{
1255 		UINT32 *src = (UINT32 *)srcbitmap->base + (y - srcbounds->min_y) * srcbitmap->rowpixels + (sect.min_x - srcbounds->min_x);
1256 		UINT32 *dest = (UINT32 *)dstbitmap->base + y * dstbitmap->rowpixels + sect.min_x;
1257 
1258 		/* loop over columns */
1259 		for (x = 0; x < width; x++)
1260 		{
1261 			UINT32 pix = src[x];
1262 
1263 			/* just add and clamp */
1264 			if (pix != transparent_color)
1265 				dest[x] = add_and_clamp(pix, dest[x]);
1266 		}
1267 	}
1268 }
1269 
1270 
1271 
1272 /*-------------------------------------------------
1273 	cmy_blend_intersecting_rect - CMY blend an
1274 	artwork piece into a bitmap
1275 -------------------------------------------------*/
1276 
cmy_blend_intersecting_rect(struct mame_bitmap * dstprebitmap,struct mame_bitmap * dstyrgbbitmap,const struct rectangle * dstbounds,struct mame_bitmap * srcprebitmap,struct mame_bitmap * srcyrgbbitmap,const struct rectangle * srcbounds,UINT8 blendflags)1277 static void cmy_blend_intersecting_rect(
1278 	struct mame_bitmap *dstprebitmap, struct mame_bitmap *dstyrgbbitmap, const struct rectangle *dstbounds,
1279 	struct mame_bitmap *srcprebitmap, struct mame_bitmap *srcyrgbbitmap, const struct rectangle *srcbounds,
1280 	UINT8 blendflags)
1281 {
1282 	struct rectangle sect = *srcbounds;
1283 	int x, y, width;
1284 
1285 	/* compute the intersection and resulting width */
1286 	sect_rect(&sect, dstbounds);
1287 	width = sect.max_x - sect.min_x + 1;
1288 
1289 	/* loop over rows */
1290 	for (y = sect.min_y; y <= sect.max_y; y++)
1291 	{
1292 		UINT32 *srcpre = (UINT32 *)srcprebitmap->base + (y - srcbounds->min_y) * srcprebitmap->rowpixels + (sect.min_x - srcbounds->min_x);
1293 		UINT32 *srcyrgb = (UINT32 *)srcyrgbbitmap->base + (y - srcbounds->min_y) * srcyrgbbitmap->rowpixels + (sect.min_x - srcbounds->min_x);
1294 		UINT32 *destpre = (UINT32 *)dstprebitmap->base + y * dstprebitmap->rowpixels + sect.min_x;
1295 		UINT32 *destyrgb = (UINT32 *)dstyrgbbitmap->base + y * dstyrgbbitmap->rowpixels + sect.min_x;
1296 
1297 		/* loop over columns */
1298 		for (x = 0; x < width; x++)
1299 		{
1300 			UINT32 spre = srcpre[x];
1301 			UINT32 dpre = destpre[x];
1302 			UINT32 syrgb = srcyrgb[x];
1303 			UINT32 dyrgb = destyrgb[x];
1304 
1305 			/* handle "non-blending" mode */
1306 			if (blendflags & OVERLAY_FLAG_NOBLEND)
1307 			{
1308 				if ((spre & nonalpha_mask) && spre >= dpre)
1309 				{
1310 					destpre[x] = spre;
1311 					destyrgb[x] = syrgb;
1312 				}
1313 			}
1314 
1315 			/* simple copy if nothing at the dest */
1316 			else if (dpre == transparent_color && dyrgb == 0)
1317 			{
1318 				destpre[x] = spre;
1319 				destyrgb[x] = syrgb;
1320 			}
1321 			else
1322 			{
1323 				/* subtract CMY and alpha from each pixel */
1324 				int sc = (~syrgb >> rshift) & 0xff;
1325 				int sm = (~syrgb >> gshift) & 0xff;
1326 				int sy = (~syrgb >> bshift) & 0xff;
1327 				int sa = (~spre >> ashift) & 0xff;
1328 				int dc = (~dyrgb >> rshift) & 0xff;
1329 				int dm = (~dyrgb >> gshift) & 0xff;
1330 				int dy = (~dyrgb >> bshift) & 0xff;
1331 				int da = (~dpre >> ashift) & 0xff;
1332 				int dr, dg, db;
1333 				int max;
1334 
1335 				/* add and clamp the alphas */
1336 				da += sa;
1337 				if (da > 0xff) da = 0xff;
1338 
1339 				/* add the CMY */
1340 				dc += sc;
1341 				dm += sm;
1342 				dy += sy;
1343 
1344 				/* compute the maximum intensity */
1345 				max = (dc > dm) ? dc : dm;
1346 				max = (dy > max) ? dy : max;
1347 
1348 				/* if that's out of range, scale by it */
1349 				if (max > 0xff)
1350 				{
1351 					dc = (dc * 0xff) / max;
1352 					dm = (dm * 0xff) / max;
1353 					dy = (dy * 0xff) / max;
1354 				}
1355 
1356 				/* convert back to RGB */
1357 				dr = dc ^ 0xff;
1358 				dg = dm ^ 0xff;
1359 				db = dy ^ 0xff;
1360 
1361 				/* recompute the two pixels */
1362 				destpre[x] = compute_pre_pixel(da,dr,dg,db);
1363 				destyrgb[x] = compute_yrgb_pixel(da,dr,dg,db);
1364 			}
1365 		}
1366 	}
1367 }
1368 
1369 
1370 
1371 #if 0
1372 #pragma mark -
1373 #pragma mark GAME BITMAP PROCESSING
1374 #endif
1375 
1376 /*-------------------------------------------------
1377 	update_palette - update any dirty palette
1378 	entries
1379 -------------------------------------------------*/
1380 
update_palette_lookup(struct mame_display * display)1381 static void update_palette_lookup(struct mame_display *display)
1382 {
1383 	int i, j;
1384 
1385 	/* loop over dirty colors in batches of 32 */
1386 	for (i = 0; i < display->game_palette_entries; i += 32)
1387 	{
1388 		UINT32 dirtyflags = display->game_palette_dirty[i / 32];
1389 		if (dirtyflags)
1390 		{
1391 			display->game_palette_dirty[i / 32] = 0;
1392 
1393 			/* loop over all 32 bits and update dirty entries */
1394 			for (j = 0; j < 32; j++, dirtyflags >>= 1)
1395 				if (dirtyflags & 1)
1396 				{
1397 					/* extract the RGB values */
1398 					rgb_t rgbvalue = display->game_palette[i + j];
1399 					int r = RGB_RED(rgbvalue);
1400 					int g = RGB_GREEN(rgbvalue);
1401 					int b = RGB_BLUE(rgbvalue);
1402 
1403 					/* update the lookup table */
1404 					palette_lookup[i + j] = ASSEMBLE_ARGB(0, r, g, b);
1405 				}
1406 		}
1407 	}
1408 }
1409 
1410 
1411 
1412 /*-------------------------------------------------
1413 	render_game_bitmap - render the game bitmap
1414 	raw
1415 -------------------------------------------------*/
1416 
1417 #define PIXEL(x,y,srcdstbase,srcdstrpix,bits)	(*((UINT##bits *)srcdstbase##base + (y) * srcdstrpix##rowpixels + (x)))
1418 
render_game_bitmap(struct mame_bitmap * bitmap,const rgb_t * palette,struct mame_display * display)1419 static void render_game_bitmap(struct mame_bitmap *bitmap, const rgb_t *palette, struct mame_display *display)
1420 {
1421 	int srcrowpixels = bitmap->rowpixels;
1422 	int dstrowpixels = final->rowpixels;
1423 	void *srcbase, *dstbase;
1424 	int width, height;
1425 	int x, y;
1426 
1427 	/* compute common parameters */
1428 	width = Machine->absolute_visible_area.max_x - Machine->absolute_visible_area.min_x + 1;
1429 	height = Machine->absolute_visible_area.max_y - Machine->absolute_visible_area.min_y + 1;
1430 	srcbase = (UINT8 *)bitmap->base + Machine->absolute_visible_area.min_y * bitmap->rowbytes;
1431 	dstbase = (UINT8 *)final->base + gamerect.min_y * final->rowbytes + gamerect.min_x * sizeof(UINT32);
1432 
1433 	/* vector case */
1434 	if (display->changed_flags & VECTOR_PIXELS_CHANGED)
1435 	{
1436 		vector_pixel_t offset = VECTOR_PIXEL(gamerect.min_x, gamerect.min_y);
1437 		vector_pixel_t *list = display->vector_dirty_pixels;
1438 
1439 		/* 16/15bpp case */
1440 		if (bitmap->depth != 32)
1441 		{
1442 			while (*list != VECTOR_PIXEL_END)
1443 			{
1444 				vector_pixel_t coords = *list;
1445 				x = VECTOR_PIXEL_X(coords);
1446 				y = VECTOR_PIXEL_Y(coords);
1447 				*list++ = coords + offset;
1448 				PIXEL(x,y,dst,dst,32) = palette[PIXEL(x,y,src,src,16)];
1449 			}
1450 		}
1451 
1452 		/* 32bpp case */
1453 		else
1454 		{
1455 			while (*list != VECTOR_PIXEL_END)
1456 			{
1457 				vector_pixel_t coords = *list;
1458 				x = VECTOR_PIXEL_X(coords);
1459 				y = VECTOR_PIXEL_Y(coords);
1460 				*list++ = coords + offset;
1461 				PIXEL(x,y,dst,dst,32) = PIXEL(x,y,src,src,32);
1462 			}
1463 		}
1464 	}
1465 
1466 	/* 1x scale */
1467 	else if (gamescale == 1)
1468 	{
1469 		/* 16/15bpp case */
1470 		if (bitmap->depth != 32)
1471 		{
1472 			for (y = 0; y < height; y++)
1473 			{
1474 				UINT16 *src = (UINT16 *)srcbase + y * srcrowpixels + Machine->absolute_visible_area.min_x;
1475 				UINT32 *dst = (UINT32 *)dstbase + y * dstrowpixels;
1476 				for (x = 0; x < width; x++)
1477 					*dst++ = palette[*src++];
1478 			}
1479 		}
1480 
1481 		/* 32bpp case */
1482 		else
1483 		{
1484 			for (y = 0; y < height; y++)
1485 			{
1486 				UINT32 *src = (UINT32 *)srcbase + y * srcrowpixels + Machine->absolute_visible_area.min_x;
1487 				UINT32 *dst = (UINT32 *)dstbase + y * dstrowpixels;
1488 				for (x = 0; x < width; x++)
1489 					*dst++ = *src++;
1490 			}
1491 		}
1492 	}
1493 
1494 	/* 2x scale */
1495 	else if (gamescale == 2)
1496 	{
1497 		/* 16/15bpp case */
1498 		if (bitmap->depth != 32)
1499 		{
1500 			for (y = 0; y < height; y++)
1501 			{
1502 				UINT16 *src = (UINT16 *)srcbase + y * srcrowpixels + Machine->absolute_visible_area.min_x;
1503 				UINT32 *dst = (UINT32 *)dstbase + y * 2 * dstrowpixels;
1504 				for (x = 0; x < width; x++)
1505 				{
1506 					UINT32 val = palette[*src++];
1507 					dst[0] = val;
1508 					dst[1] = val;
1509 					dst[dstrowpixels] = val;
1510 					dst[dstrowpixels + 1] = val;
1511 					dst += 2;
1512 				}
1513 			}
1514 		}
1515 
1516 		/* 32bpp case */
1517 		else
1518 		{
1519 			for (y = 0; y < height; y++)
1520 			{
1521 				UINT32 *src = (UINT32 *)srcbase + y * srcrowpixels + Machine->absolute_visible_area.min_x;
1522 				UINT32 *dst = (UINT32 *)dstbase + y * 2 * dstrowpixels;
1523 				for (x = 0; x < width; x++)
1524 				{
1525 					UINT32 val = *src++;
1526 					dst[0] = val;
1527 					dst[1] = val;
1528 					dst[dstrowpixels] = val;
1529 					dst[dstrowpixels + 1] = val;
1530 					dst += 2;
1531 				}
1532 			}
1533 		}
1534 	}
1535 	/* Any other scale. For performance at 2x we don't use the below code and handle separately. */
1536 	else
1537 	{
1538 		/* 16/15bpp case */
1539 		if (bitmap->depth != 32)
1540 		{
1541 			for (y = 0; y < height; y++)
1542 			{
1543 				UINT16 *src = (UINT16 *)srcbase + y * srcrowpixels + Machine->absolute_visible_area.min_x;
1544 				UINT32 *dst = (UINT32 *)dstbase + y * gamescale * dstrowpixels;
1545 				for (x = 0; x < width; x++)
1546 				{
1547 					UINT32 val = palette[*src++];
1548 					int r;
1549                                         for (r = 0; r < gamescale; r++) {
1550 					    int c;
1551                                             for (c = 0; c < gamescale; c++)
1552                                                 dst[dstrowpixels*r + c] = val;
1553 					}
1554                                         dst += gamescale;
1555 				}
1556 			}
1557 		}
1558 
1559 		/* 32bpp case */
1560 		else
1561 		{
1562 			for (y = 0; y < height; y++)
1563 			{
1564 				UINT32 *src = (UINT32 *)srcbase + y * srcrowpixels + Machine->absolute_visible_area.min_x;
1565 				UINT32 *dst = (UINT32 *)dstbase + y * gamescale * dstrowpixels;
1566 				for (x = 0; x < width; x++)
1567 				{
1568 					UINT32 val = *src++;
1569 					int r;
1570                                         for (r = 0; r < gamescale; r++) {
1571 					    int c;
1572                                             for (c = 0; c < gamescale; c++)
1573                                                 dst[dstrowpixels*r + c] = val;
1574 					}
1575                                         dst += gamescale;
1576 				}
1577 			}
1578 		}
1579 	}
1580 }
1581 
1582 
1583 
1584 /*-------------------------------------------------
1585 	render_game_bitmap_underlay - render the game
1586 	bitmap on top of an underlay
1587 -------------------------------------------------*/
1588 
render_game_bitmap_underlay(struct mame_bitmap * bitmap,const rgb_t * palette,struct mame_display * display)1589 static void render_game_bitmap_underlay(struct mame_bitmap *bitmap, const rgb_t *palette, struct mame_display *display)
1590 {
1591 	int srcrowpixels = bitmap->rowpixels;
1592 	int dstrowpixels = final->rowpixels;
1593 	void *srcbase, *dstbase, *undbase;
1594 	int width, height;
1595 	int x, y;
1596 
1597 	/* compute common parameters */
1598 	width = Machine->absolute_visible_area.max_x - Machine->absolute_visible_area.min_x + 1;
1599 	height = Machine->absolute_visible_area.max_y - Machine->absolute_visible_area.min_y + 1;
1600 	srcbase = (UINT8 *)bitmap->base + Machine->absolute_visible_area.min_y * bitmap->rowbytes;
1601 	dstbase = (UINT8 *)final->base + gamerect.min_y * final->rowbytes + gamerect.min_x * sizeof(UINT32);
1602 	undbase = (UINT8 *)underlay->base + gamerect.min_y * underlay->rowbytes + gamerect.min_x * sizeof(UINT32);
1603 
1604 	/* vector case */
1605 	if (display->changed_flags & VECTOR_PIXELS_CHANGED)
1606 	{
1607 		vector_pixel_t offset = VECTOR_PIXEL(gamerect.min_x, gamerect.min_y);
1608 		vector_pixel_t *list = display->vector_dirty_pixels;
1609 
1610 		/* 16/15bpp case */
1611 		if (bitmap->depth != 32)
1612 		{
1613 			while (*list != VECTOR_PIXEL_END)
1614 			{
1615 				vector_pixel_t coords = *list;
1616 				x = VECTOR_PIXEL_X(coords);
1617 				y = VECTOR_PIXEL_Y(coords);
1618 				*list++ = coords + offset;
1619 				PIXEL(x,y,dst,dst,32) = add_and_clamp(palette[PIXEL(x,y,src,src,16)], PIXEL(x,y,und,dst,32));
1620 			}
1621 		}
1622 
1623 		/* 32bpp case */
1624 		else
1625 		{
1626 			while (*list != VECTOR_PIXEL_END)
1627 			{
1628 				vector_pixel_t coords = *list;
1629 				x = VECTOR_PIXEL_X(coords);
1630 				y = VECTOR_PIXEL_Y(coords);
1631 				*list++ = coords + offset;
1632 				PIXEL(x,y,dst,dst,32) = add_and_clamp(PIXEL(x,y,src,src,32), PIXEL(x,y,und,dst,32));
1633 			}
1634 		}
1635 	}
1636 
1637 	/* 1x scale */
1638 	else if (gamescale == 1)
1639 	{
1640 		/* 16/15bpp case */
1641 		if (bitmap->depth != 32)
1642 		{
1643 			for (y = 0; y < height; y++)
1644 			{
1645 				UINT16 *src = (UINT16 *)srcbase + y * srcrowpixels + Machine->absolute_visible_area.min_x;
1646 				UINT32 *dst = (UINT32 *)dstbase + y * dstrowpixels;
1647 				UINT32 *und = (UINT32 *)undbase + y * dstrowpixels;
1648 				for (x = 0; x < width; x++)
1649 					*dst++ = add_and_clamp(palette[*src++], *und++);
1650 			}
1651 		}
1652 
1653 		/* 32bpp case */
1654 		else
1655 		{
1656 			for (y = 0; y < height; y++)
1657 			{
1658 				UINT32 *src = (UINT32 *)srcbase + y * srcrowpixels + Machine->absolute_visible_area.min_x;
1659 				UINT32 *dst = (UINT32 *)dstbase + y * dstrowpixels;
1660 				UINT32 *und = (UINT32 *)undbase + y * dstrowpixels;
1661 				for (x = 0; x < width; x++)
1662 					*dst++ = add_and_clamp(*src++, *und++);
1663 			}
1664 		}
1665 	}
1666 
1667 	/* 2x scale */
1668 	else if (gamescale == 2)
1669 	{
1670 		/* 16/15bpp case */
1671 		if (bitmap->depth != 32)
1672 		{
1673 			for (y = 0; y < height; y++)
1674 			{
1675 				UINT16 *src = (UINT16 *)srcbase + y * srcrowpixels + Machine->absolute_visible_area.min_x;
1676 				UINT32 *dst = (UINT32 *)dstbase + y * 2 * dstrowpixels;
1677 				UINT32 *und = (UINT32 *)undbase + y * 2 * dstrowpixels;
1678 				for (x = 0; x < width; x++)
1679 				{
1680 					UINT32 val = palette[*src++];
1681 					dst[0] = add_and_clamp(val, und[0]);
1682 					dst[1] = add_and_clamp(val, und[1]);
1683 					dst[dstrowpixels] = add_and_clamp(val, und[dstrowpixels]);
1684 					dst[dstrowpixels + 1] = add_and_clamp(val, und[dstrowpixels + 1]);
1685 					dst += 2;
1686 					und += 2;
1687 				}
1688 			}
1689 		}
1690 
1691 		/* 32bpp case */
1692 		else
1693 		{
1694 			for (y = 0; y < height; y++)
1695 			{
1696 				UINT32 *src = (UINT32 *)srcbase + y * srcrowpixels + Machine->absolute_visible_area.min_x;
1697 				UINT32 *dst = (UINT32 *)dstbase + y * 2 * dstrowpixels;
1698 				UINT32 *und = (UINT32 *)undbase + y * 2 * dstrowpixels;
1699 				for (x = 0; x < width; x++)
1700 				{
1701 					UINT32 val = *src++;
1702 					dst[0] = add_and_clamp(val, und[0]);
1703 					dst[1] = add_and_clamp(val, und[1]);
1704 					dst[dstrowpixels] = add_and_clamp(val, und[dstrowpixels]);
1705 					dst[dstrowpixels + 1] = add_and_clamp(val, und[dstrowpixels + 1]);
1706 					dst += 2;
1707 					und += 2;
1708 				}
1709 			}
1710 		}
1711 	}
1712 	/* Any other scale. For performance at 2x we don't use the below code and handle separately. */
1713 	else
1714 	{
1715 		/* 16/15bpp case */
1716 		if (bitmap->depth != 32)
1717 		{
1718 			for (y = 0; y < height; y++)
1719 			{
1720 				UINT16 *src = (UINT16 *)srcbase + y * srcrowpixels + Machine->absolute_visible_area.min_x;
1721 				UINT32 *dst = (UINT32 *)dstbase + y * gamescale * dstrowpixels;
1722 				UINT32 *und = (UINT32 *)undbase + y * gamescale * dstrowpixels;
1723 				for (x = 0; x < width; x++)
1724 				{
1725 					UINT32 val = palette[*src++];
1726 					int r;
1727                                         for (r = 0; r < gamescale; r++) {
1728 					    int c;
1729                                             for (c = 0; c < gamescale; c++)
1730                                                 dst[dstrowpixels*r + c] = add_and_clamp(val, und[dstrowpixels*r + c]);
1731 					}
1732                                         dst += gamescale;
1733 					und += gamescale;
1734 				}
1735 			}
1736 		}
1737 
1738 		/* 32bpp case */
1739 		else
1740 		{
1741 			for (y = 0; y < height; y++)
1742 			{
1743 				UINT32 *src = (UINT32 *)srcbase + y * srcrowpixels + Machine->absolute_visible_area.min_x;
1744 				UINT32 *dst = (UINT32 *)dstbase + y * gamescale * dstrowpixels;
1745 				UINT32 *und = (UINT32 *)undbase + y * gamescale * dstrowpixels;
1746 				for (x = 0; x < width; x++)
1747 				{
1748 					UINT32 val = *src++;
1749 					int r;
1750                                         for (r = 0; r < gamescale; r++) {
1751 					    int c;
1752                                             for (c = 0; c < gamescale; c++)
1753                                                 dst[dstrowpixels*r + c] = add_and_clamp(val, und[dstrowpixels*r + c]);
1754 					}
1755 					dst += gamescale;
1756 					und += gamescale;
1757 				}
1758 			}
1759 		}
1760 	}
1761 }
1762 
1763 
1764 
1765 /*-------------------------------------------------
1766 	render_game_bitmap_overlay - render the game
1767 	bitmap blended with an overlay
1768 -------------------------------------------------*/
1769 
render_game_bitmap_overlay(struct mame_bitmap * bitmap,const rgb_t * palette,struct mame_display * display)1770 static void render_game_bitmap_overlay(struct mame_bitmap *bitmap, const rgb_t *palette, struct mame_display *display)
1771 {
1772 	int srcrowpixels = bitmap->rowpixels;
1773 	int dstrowpixels = final->rowpixels;
1774 	void *srcbase, *dstbase, *overbase, *overyrgbbase;
1775 	int width, height;
1776 	int x, y;
1777 
1778 	/* compute common parameters */
1779 	width = Machine->absolute_visible_area.max_x - Machine->absolute_visible_area.min_x + 1;
1780 	height = Machine->absolute_visible_area.max_y - Machine->absolute_visible_area.min_y + 1;
1781 	srcbase = (UINT8 *)bitmap->base + Machine->absolute_visible_area.min_y * bitmap->rowbytes;
1782 	dstbase = (UINT8 *)final->base + gamerect.min_y * final->rowbytes + gamerect.min_x * sizeof(UINT32);
1783 	overbase = (UINT8 *)overlay->base + gamerect.min_y * overlay->rowbytes + gamerect.min_x * sizeof(UINT32);
1784 	overyrgbbase = (UINT8 *)overlay_yrgb->base + gamerect.min_y * overlay_yrgb->rowbytes + gamerect.min_x * sizeof(UINT32);
1785 
1786 	/* vector case */
1787 	if (display->changed_flags & VECTOR_PIXELS_CHANGED)
1788 	{
1789 		vector_pixel_t offset = VECTOR_PIXEL(gamerect.min_x, gamerect.min_y);
1790 		vector_pixel_t *list = display->vector_dirty_pixels;
1791 
1792 		/* 16/15bpp case */
1793 		if (bitmap->depth != 32)
1794 		{
1795 			while (*list != VECTOR_PIXEL_END)
1796 			{
1797 				vector_pixel_t coords = *list;
1798 				x = VECTOR_PIXEL_X(coords);
1799 				y = VECTOR_PIXEL_Y(coords);
1800 				*list++ = coords + offset;
1801 				PIXEL(x,y,dst,dst,32) = blend_over(palette[PIXEL(x,y,src,src,16)], PIXEL(x,y,over,dst,32), PIXEL(x,y,overyrgb,dst,32));
1802 			}
1803 		}
1804 
1805 		/* 32bpp case */
1806 		else
1807 		{
1808 			while (*list != VECTOR_PIXEL_END)
1809 			{
1810 				vector_pixel_t coords = *list;
1811 				x = VECTOR_PIXEL_X(coords);
1812 				y = VECTOR_PIXEL_Y(coords);
1813 				*list++ = coords + offset;
1814 				PIXEL(x,y,dst,dst,32) = blend_over(PIXEL(x,y,src,src,32), PIXEL(x,y,over,dst,32), PIXEL(x,y,overyrgb,dst,32));
1815 			}
1816 		}
1817 	}
1818 
1819 	/* 1x scale */
1820 	else if (gamescale == 1)
1821 	{
1822 		/* 16/15bpp case */
1823 		if (bitmap->depth != 32)
1824 		{
1825 			for (y = 0; y < height; y++)
1826 			{
1827 				UINT16 *src = (UINT16 *)srcbase + y * srcrowpixels + Machine->absolute_visible_area.min_x;
1828 				UINT32 *dst = (UINT32 *)dstbase + y * dstrowpixels;
1829 				UINT32 *over = (UINT32 *)overbase + y * dstrowpixels;
1830 				UINT32 *overyrgb = (UINT32 *)overyrgbbase + y * dstrowpixels;
1831 				for (x = 0; x < width; x++)
1832 					*dst++ = blend_over(palette[*src++], *over++, *overyrgb++);
1833 			}
1834 		}
1835 
1836 		/* 32bpp case */
1837 		else
1838 		{
1839 			for (y = 0; y < height; y++)
1840 			{
1841 				UINT32 *src = (UINT32 *)srcbase + y * srcrowpixels + Machine->absolute_visible_area.min_x;
1842 				UINT32 *dst = (UINT32 *)dstbase + y * dstrowpixels;
1843 				UINT32 *over = (UINT32 *)overbase + y * dstrowpixels;
1844 				UINT32 *overyrgb = (UINT32 *)overyrgbbase + y * dstrowpixels;
1845 				for (x = 0; x < width; x++)
1846 					*dst++ = blend_over(*src++, *over++, *overyrgb++);
1847 			}
1848 		}
1849 	}
1850 
1851 	/* 2x scale */
1852 	else if (gamescale == 2)
1853 	{
1854 		/* 16/15bpp case */
1855 		if (bitmap->depth != 32)
1856 		{
1857 			for (y = 0; y < height; y++)
1858 			{
1859 				UINT16 *src = (UINT16 *)srcbase + y * srcrowpixels + Machine->absolute_visible_area.min_x;
1860 				UINT32 *dst = (UINT32 *)dstbase + y * 2 * dstrowpixels;
1861 				UINT32 *over = (UINT32 *)overbase + y * 2 * dstrowpixels;
1862 				UINT32 *overyrgb = (UINT32 *)overyrgbbase + y * 2 * dstrowpixels;
1863 				for (x = 0; x < width; x++)
1864 				{
1865 					UINT32 val = palette[*src++];
1866 					dst[0] = blend_over(val, over[0], overyrgb[0]);
1867 					dst[1] = blend_over(val, over[1], overyrgb[1]);
1868 					dst[dstrowpixels] = blend_over(val, over[dstrowpixels], overyrgb[dstrowpixels]);
1869 					dst[dstrowpixels + 1] = blend_over(val, over[dstrowpixels + 1], overyrgb[dstrowpixels + 1]);
1870 					dst += 2;
1871 					over += 2;
1872 					overyrgb += 2;
1873 				}
1874 			}
1875 		}
1876 
1877 		/* 32bpp case */
1878 		else
1879 		{
1880 			for (y = 0; y < height; y++)
1881 			{
1882 				UINT32 *src = (UINT32 *)srcbase + y * srcrowpixels + Machine->absolute_visible_area.min_x;
1883 				UINT32 *dst = (UINT32 *)dstbase + y * 2 * dstrowpixels;
1884 				UINT32 *over = (UINT32 *)overbase + y * 2 * dstrowpixels;
1885 				UINT32 *overyrgb = (UINT32 *)overyrgbbase + y * 2 * dstrowpixels;
1886 				for (x = 0; x < width; x++)
1887 				{
1888 					UINT32 val = *src++;
1889 					dst[0] = blend_over(val, over[0], overyrgb[0]);
1890 					dst[1] = blend_over(val, over[1], overyrgb[1]);
1891 					dst[dstrowpixels] = blend_over(val, over[dstrowpixels], overyrgb[dstrowpixels]);
1892 					dst[dstrowpixels + 1] = blend_over(val, over[dstrowpixels + 1], overyrgb[dstrowpixels + 1]);
1893 					dst += 2;
1894 					over += 2;
1895 					overyrgb += 2;
1896 				}
1897 			}
1898 		}
1899 	}
1900 	/* Any other scale. For performance at 2x we don't use the below code and handle separately. */
1901 	else
1902 	{
1903 		/* 16/15bpp case */
1904 		if (bitmap->depth != 32)
1905 		{
1906 			for (y = 0; y < height; y++)
1907 			{
1908 				UINT16 *src = (UINT16 *)srcbase + y * srcrowpixels + Machine->absolute_visible_area.min_x;
1909 				UINT32 *dst = (UINT32 *)dstbase + y * gamescale * dstrowpixels;
1910 				UINT32 *over = (UINT32 *)overbase + y * gamescale * dstrowpixels;
1911 				UINT32 *overyrgb = (UINT32 *)overyrgbbase + y * gamescale * dstrowpixels;
1912 				for (x = 0; x < width; x++)
1913 				{
1914 					UINT32 val = palette[*src++];
1915 					int r;
1916                                         for (r = 0; r < gamescale; r++) {
1917 					    int c;
1918                                             for (c = 0; c < gamescale; c++)
1919                                                 dst[dstrowpixels*r + c] = blend_over(val, over[dstrowpixels*r + c], overyrgb[dstrowpixels*r + c]);
1920 					}
1921 					dst += gamescale;
1922 					over += gamescale;
1923 					overyrgb += gamescale;
1924 				}
1925 			}
1926 		}
1927 
1928 		/* 32bpp case */
1929 		else
1930 		{
1931 			for (y = 0; y < height; y++)
1932 			{
1933 				UINT32 *src = (UINT32 *)srcbase + y * srcrowpixels + Machine->absolute_visible_area.min_x;
1934 				UINT32 *dst = (UINT32 *)dstbase + y * gamescale * dstrowpixels;
1935 				UINT32 *over = (UINT32 *)overbase + y * gamescale * dstrowpixels;
1936 				UINT32 *overyrgb = (UINT32 *)overyrgbbase + y * gamescale * dstrowpixels;
1937 				for (x = 0; x < width; x++)
1938 				{
1939 					UINT32 val = *src++;
1940 					int r;
1941                                         for (r = 0; r < gamescale; r++) {
1942 					    int c;
1943                                             for (c = 0; c < gamescale; c++)
1944                                                 dst[dstrowpixels*r + c] = blend_over(val, over[dstrowpixels*r + c], overyrgb[dstrowpixels*r + c]);
1945 					}
1946 					dst += gamescale;
1947 					over += gamescale;
1948 					overyrgb += gamescale;
1949 				}
1950 			}
1951 		}
1952 	}
1953 }
1954 
1955 
1956 
1957 /*-------------------------------------------------
1958 	render_game_bitmap_underlay_overlay - render
1959 	the game bitmap blended with an overlay and
1960 	added to an underlay
1961 -------------------------------------------------*/
1962 
render_game_bitmap_underlay_overlay(struct mame_bitmap * bitmap,const rgb_t * palette,struct mame_display * display)1963 static void render_game_bitmap_underlay_overlay(struct mame_bitmap *bitmap, const rgb_t *palette, struct mame_display *display)
1964 {
1965 	int srcrowpixels = bitmap->rowpixels;
1966 	int dstrowpixels = final->rowpixels;
1967 	void *srcbase, *dstbase, *undbase, *overbase, *overyrgbbase;
1968 	int width, height;
1969 	int x, y;
1970 
1971 	/* compute common parameters */
1972 	width = Machine->absolute_visible_area.max_x - Machine->absolute_visible_area.min_x + 1;
1973 	height = Machine->absolute_visible_area.max_y - Machine->absolute_visible_area.min_y + 1;
1974 	srcbase = (UINT8 *)bitmap->base + Machine->absolute_visible_area.min_y * bitmap->rowbytes;
1975 	dstbase = (UINT8 *)final->base + gamerect.min_y * final->rowbytes + gamerect.min_x * sizeof(UINT32);
1976 	undbase = (UINT8 *)underlay->base + gamerect.min_y * underlay->rowbytes + gamerect.min_x * sizeof(UINT32);
1977 	overbase = (UINT8 *)overlay->base + gamerect.min_y * overlay->rowbytes + gamerect.min_x * sizeof(UINT32);
1978 	overyrgbbase = (UINT8 *)overlay_yrgb->base + gamerect.min_y * overlay_yrgb->rowbytes + gamerect.min_x * sizeof(UINT32);
1979 
1980 	/* vector case */
1981 	if (display->changed_flags & VECTOR_PIXELS_CHANGED)
1982 	{
1983 		vector_pixel_t offset = VECTOR_PIXEL(gamerect.min_x, gamerect.min_y);
1984 		vector_pixel_t *list = display->vector_dirty_pixels;
1985 
1986 		/* 16/15bpp case */
1987 		if (bitmap->depth != 32)
1988 		{
1989 			while (*list != VECTOR_PIXEL_END)
1990 			{
1991 				vector_pixel_t coords = *list;
1992 				x = VECTOR_PIXEL_X(coords);
1993 				y = VECTOR_PIXEL_Y(coords);
1994 				*list++ = coords + offset;
1995 				PIXEL(x,y,dst,dst,32) = add_and_clamp(blend_over(palette[PIXEL(x,y,src,src,16)], PIXEL(x,y,over,dst,32), PIXEL(x,y,overyrgb,dst,32)), PIXEL(x,y,und,dst,32));
1996 			}
1997 		}
1998 
1999 		/* 32bpp case */
2000 		else
2001 		{
2002 			while (*list != VECTOR_PIXEL_END)
2003 			{
2004 				vector_pixel_t coords = *list;
2005 				x = VECTOR_PIXEL_X(coords);
2006 				y = VECTOR_PIXEL_Y(coords);
2007 				*list++ = coords + offset;
2008 				PIXEL(x,y,dst,dst,32) = add_and_clamp(blend_over(PIXEL(x,y,src,src,32), PIXEL(x,y,over,dst,32), PIXEL(x,y,overyrgb,dst,32)), PIXEL(x,y,und,dst,32));
2009 			}
2010 		}
2011 	}
2012 
2013 	/* 1x scale */
2014 	else if (gamescale == 1)
2015 	{
2016 		/* 16/15bpp case */
2017 		if (bitmap->depth != 32)
2018 		{
2019 			for (y = 0; y < height; y++)
2020 			{
2021 				UINT16 *src = (UINT16 *)srcbase + y * srcrowpixels + Machine->absolute_visible_area.min_x;
2022 				UINT32 *dst = (UINT32 *)dstbase + y * dstrowpixels;
2023 				UINT32 *und = (UINT32 *)undbase + y * dstrowpixels;
2024 				UINT32 *over = (UINT32 *)overbase + y * dstrowpixels;
2025 				UINT32 *overyrgb = (UINT32 *)overyrgbbase + y * dstrowpixels;
2026 				for (x = 0; x < width; x++)
2027 					*dst++ = add_and_clamp(blend_over(palette[*src++], *over++, *overyrgb++), *und++);
2028 			}
2029 		}
2030 
2031 		/* 32bpp case */
2032 		else
2033 		{
2034 			for (y = 0; y < height; y++)
2035 			{
2036 				UINT32 *src = (UINT32 *)srcbase + y * srcrowpixels + Machine->absolute_visible_area.min_x;
2037 				UINT32 *dst = (UINT32 *)dstbase + y * dstrowpixels;
2038 				UINT32 *und = (UINT32 *)undbase + y * dstrowpixels;
2039 				UINT32 *over = (UINT32 *)overbase + y * dstrowpixels;
2040 				UINT32 *overyrgb = (UINT32 *)overyrgbbase + y * dstrowpixels;
2041 				for (x = 0; x < width; x++)
2042 					*dst++ = add_and_clamp(blend_over(*src++, *over++, *overyrgb++), *und++);
2043 			}
2044 		}
2045 	}
2046 
2047 	/* 2x scale */
2048 	else if (gamescale == 2)
2049 	{
2050 		/* 16/15bpp case */
2051 		if (bitmap->depth != 32)
2052 		{
2053 			for (y = 0; y < height; y++)
2054 			{
2055 				UINT16 *src = (UINT16 *)srcbase + y * srcrowpixels + Machine->absolute_visible_area.min_x;
2056 				UINT32 *dst = (UINT32 *)dstbase + y * 2 * dstrowpixels;
2057 				UINT32 *und = (UINT32 *)undbase + y * 2 * dstrowpixels;
2058 				UINT32 *over = (UINT32 *)overbase + y * 2 * dstrowpixels;
2059 				UINT32 *overyrgb = (UINT32 *)overyrgbbase + y * 2 * dstrowpixels;
2060 				for (x = 0; x < width; x++)
2061 				{
2062 					UINT32 val = palette[*src++];
2063 					dst[0] = add_and_clamp(blend_over(val, over[0], overyrgb[0]), und[0]);
2064 					dst[1] = add_and_clamp(blend_over(val, over[1], overyrgb[1]), und[1]);
2065 					dst[dstrowpixels] = add_and_clamp(blend_over(val, over[dstrowpixels], overyrgb[dstrowpixels]), und[dstrowpixels]);
2066 					dst[dstrowpixels + 1] = add_and_clamp(blend_over(val, over[dstrowpixels + 1], overyrgb[dstrowpixels + 1]), und[dstrowpixels + 1]);
2067 					dst += 2;
2068 					und += 2;
2069 					over += 2;
2070 					overyrgb += 2;
2071 				}
2072 			}
2073 		}
2074 
2075 		/* 32bpp case */
2076 		else
2077 		{
2078 			for (y = 0; y < height; y++)
2079 			{
2080 				UINT32 *src = (UINT32 *)srcbase + y * srcrowpixels + Machine->absolute_visible_area.min_x;
2081 				UINT32 *dst = (UINT32 *)dstbase + y * 2 * dstrowpixels;
2082 				UINT32 *und = (UINT32 *)undbase + y * 2 * dstrowpixels;
2083 				UINT32 *over = (UINT32 *)overbase + y * 2 * dstrowpixels;
2084 				UINT32 *overyrgb = (UINT32 *)overyrgbbase + y * 2 * dstrowpixels;
2085 				for (x = 0; x < width; x++)
2086 				{
2087 					UINT32 val = *src++;
2088 					dst[0] = add_and_clamp(blend_over(val, over[0], overyrgb[0]), und[0]);
2089 					dst[1] = add_and_clamp(blend_over(val, over[1], overyrgb[1]), und[1]);
2090 					dst[dstrowpixels] = add_and_clamp(blend_over(val, over[dstrowpixels], overyrgb[dstrowpixels]), und[dstrowpixels]);
2091 					dst[dstrowpixels + 1] = add_and_clamp(blend_over(val, over[dstrowpixels + 1], overyrgb[dstrowpixels + 1]), und[dstrowpixels + 1]);
2092 					dst += 2;
2093 					und += 2;
2094 					over += 2;
2095 					overyrgb += 2;
2096 				}
2097 			}
2098 		}
2099 	}
2100 	/* Any other scale. For performance at 2x we don't use the below code and handle separately. */
2101 	else
2102 	{
2103 		/* 16/15bpp case */
2104 		if (bitmap->depth != 32)
2105 		{
2106 			for (y = 0; y < height; y++)
2107 			{
2108 				UINT16 *src = (UINT16 *)srcbase + y * srcrowpixels + Machine->absolute_visible_area.min_x;
2109 				UINT32 *dst = (UINT32 *)dstbase + y * gamescale * dstrowpixels;
2110 				UINT32 *und = (UINT32 *)undbase + y * gamescale * dstrowpixels;
2111 				UINT32 *over = (UINT32 *)overbase + y * gamescale * dstrowpixels;
2112 				UINT32 *overyrgb = (UINT32 *)overyrgbbase + y * gamescale * dstrowpixels;
2113 				for (x = 0; x < width; x++)
2114 				{
2115 					UINT32 val = palette[*src++];
2116 					int r;
2117                                         for (r = 0; r < gamescale; r++) {
2118 					    int c;
2119                                             for (c = 0; c < gamescale; c++)
2120                                                 dst[dstrowpixels*r + c] = add_and_clamp(blend_over(val, over[dstrowpixels*r + c], overyrgb[dstrowpixels*r + c]), und[dstrowpixels*r + c]);
2121 					}
2122 					dst += gamescale;
2123 					und += gamescale;
2124 					over += gamescale;
2125 					overyrgb += gamescale;
2126 				}
2127 			}
2128 		}
2129 
2130 		/* 32bpp case */
2131 		else
2132 		{
2133 			for (y = 0; y < height; y++)
2134 			{
2135 				UINT32 *src = (UINT32 *)srcbase + y * srcrowpixels + Machine->absolute_visible_area.min_x;
2136 				UINT32 *dst = (UINT32 *)dstbase + y * gamescale * dstrowpixels;
2137 				UINT32 *und = (UINT32 *)undbase + y * gamescale * dstrowpixels;
2138 				UINT32 *over = (UINT32 *)overbase + y * gamescale * dstrowpixels;
2139 				UINT32 *overyrgb = (UINT32 *)overyrgbbase + y * gamescale * dstrowpixels;
2140 				for (x = 0; x < width; x++)
2141 				{
2142 					UINT32 val = *src++;
2143 					int r;
2144                                         for (r = 0; r < gamescale; r++) {
2145 					    int c;
2146                                             for (c = 0; c < gamescale; c++)
2147                                                 dst[dstrowpixels*r + c] = add_and_clamp(blend_over(val, over[dstrowpixels*r + c], overyrgb[dstrowpixels*r + c]), und[dstrowpixels*r + c]);
2148 					}
2149 					dst += gamescale;
2150 					und += gamescale;
2151 					over += gamescale;
2152 					overyrgb += gamescale;
2153 				}
2154 			}
2155 		}
2156 	}
2157 }
2158 
2159 
2160 
2161 /*-------------------------------------------------
2162 	render_ui_overlay - render the UI overlay
2163 -------------------------------------------------*/
2164 
render_ui_overlay(struct mame_bitmap * bitmap,UINT32 * dirty,const rgb_t * palette,struct mame_display * display)2165 static void render_ui_overlay(struct mame_bitmap *bitmap, UINT32 *dirty, const rgb_t *palette, struct mame_display *display)
2166 {
2167 	int srcrowpixels = bitmap->rowpixels;
2168 	int dstrowpixels = final->rowpixels;
2169 	void *srcbase, *dstbase;
2170 	int width, height;
2171 	int x, y, h;
2172 
2173 	/* compute common parameters */
2174 	width = bitmap->width;
2175 	height = bitmap->height;
2176 	srcbase = bitmap->base;
2177 	dstbase = final->base;
2178 
2179 	/* 16/15bpp case */
2180 	if (bitmap->depth != 32)
2181 	{
2182 		for (y = 0; y < height; y++)
2183 		{
2184 			UINT16 *src = (UINT16 *)srcbase + y * srcrowpixels;
2185 			UINT32 *dst = (UINT32 *)dstbase + y * dstrowpixels;
2186 			UINT32 *hint = &dirty[y * MAX_HINTS_PER_SCANLINE];
2187 			for (h = 0; h < MAX_HINTS_PER_SCANLINE && hint[h] != 0; h++)
2188 			{
2189 				int start = hint[h] >> 16;
2190 				int stop = hint[h] & 0xffff;
2191 				hint[h] = 0;
2192 
2193 				for (x = start; x <= stop; x++)
2194 				{
2195 					int pix = src[x];
2196 					if (pix != UI_TRANSPARENT_COLOR16)
2197 					{
2198 						dst[x] = palette[pix];
2199 						src[x] = UI_TRANSPARENT_COLOR16;
2200 					}
2201 				}
2202 			}
2203 		}
2204 	}
2205 
2206 	/* 32bpp case */
2207 	else
2208 	{
2209 		for (y = 0; y < height; y++)
2210 		{
2211 			UINT32 *src = (UINT32 *)srcbase + y * srcrowpixels;
2212 			UINT32 *dst = (UINT32 *)dstbase + y * dstrowpixels;
2213 			UINT32 *hint = &dirty[y * MAX_HINTS_PER_SCANLINE];
2214 			for (h = 0; h < MAX_HINTS_PER_SCANLINE && hint[h] != 0; h++)
2215 			{
2216 				int start = hint[h] >> 16;
2217 				int stop = hint[h] & 0xffff;
2218 				hint[h] = 0;
2219 
2220 				for (x = start; x <= stop; x++)
2221 				{
2222 					int pix = src[x];
2223 					if (pix != UI_TRANSPARENT_COLOR32)
2224 					{
2225 						dst[x] = pix;
2226 						src[x] = UI_TRANSPARENT_COLOR32;
2227 					}
2228 				}
2229 			}
2230 		}
2231 	}
2232 }
2233 
2234 
2235 
2236 /*-------------------------------------------------
2237 	artwork_load_artwork_file - default MAME way
2238 	to locate an artwork file
2239 -------------------------------------------------*/
2240 
artwork_load_artwork_file(const struct GameDriver ** driver)2241 mame_file *artwork_load_artwork_file(const struct GameDriver **driver)
2242 {
2243 	char filename[100];
2244 	mame_file *artfile = NULL;
2245 
2246 	while (*driver)
2247 	{
2248 		if ((*driver)->name)
2249 		{
2250 			sprintf(filename, "%s.art", (*driver)->name);
2251 			artfile = mame_fopen((*driver)->name, filename, FILETYPE_ARTWORK, 0);
2252 			if (artfile)
2253 				break;
2254 		}
2255 		*driver = (*driver)->clone_of;
2256 	}
2257 	return artfile;
2258 }
2259 
2260 
2261 
2262 #if 0
2263 #pragma mark -
2264 #pragma mark BITMAP LOADING/MANIPULATING
2265 #endif
2266 
2267 /*-------------------------------------------------
2268 	artwork_load - locate the .art file and
2269 	read all the bitmaps
2270 -------------------------------------------------*/
2271 
artwork_load(const struct GameDriver * driver,int width,int height,const struct artwork_callbacks * callbacks)2272 static int artwork_load(const struct GameDriver *driver, int width, int height, const struct artwork_callbacks *callbacks)
2273 {
2274 	const struct overlay_piece *list = overlay_list;
2275 	struct artwork_piece *piece;
2276 	mame_file *artfile;
2277 	int result;
2278 	int opacity;
2279 
2280 	/* reset the list of artwork */
2281 	num_pieces = 0;
2282 	num_underlays = 0;
2283 	num_overlays = 0;
2284 	num_bezels = 0;
2285 	overlay_list = NULL;
2286 
2287 	/* if the user turned artwork off, bail */
2288 	if (!options.use_artwork)
2289 		return 1;
2290 
2291 	/* First process any hard-coded overlays. */
2292 	/* We handle any overlay opacity options here. */
2293 	/* A hard-coded overlay opacity of 0 means don't show overlay. */
2294 	/* A negative values will use the default opacity for the overlay. */
2295 	opacity = options.overlay_opacity;
2296 	if (opacity != 0 && list) {
2297 	    if (opacity < 0) { // Default overlay opacity
2298 		if (!generate_overlay(list, width, height))
2299 		    return 0;
2300 	    } else { // Opacity is > 0
2301                 struct overlay_piece *newlist;
2302 		/* Count elements in list */
2303 		int count = 0;
2304 		struct overlay_piece *tmp;
2305 		for (tmp = list; tmp->type != OVERLAY_TYPE_END; count++)
2306 		    tmp++;
2307 		/* Create a new list we can modify */
2308 		newlist = (struct overlay_piece *)
2309 				    calloc(count + 1, sizeof(struct overlay_piece));
2310 		memcpy(newlist, list, (count + 1)*sizeof(struct overlay_piece));
2311 		/* Modify opacity as set to user defined value */
2312 		tmp = newlist;
2313 		while (tmp->type != OVERLAY_TYPE_END) {
2314 		    tmp->color = tmp->color & ~(0xff << 24); // Clear
2315 		    tmp->color = tmp->color | (((opacity) & 0xff) << 24); // Set
2316 		    tmp++;
2317 		}
2318 		if (!generate_overlay(newlist, width, height))
2319 		    return 0;
2320 	    }
2321 	}
2322 
2323 	/* attempt to open the .ART file; if none, that's okay */
2324 	artfile = callbacks->load_artwork(&driver);
2325 	if (!artfile && !list)
2326 		return 1;
2327 
2328 	/* parse the file into pieces */
2329 	if (artfile)
2330 	{
2331 		result = parse_art_file(artfile);
2332 		mame_fclose(artfile);
2333 		if (!result)
2334 			return 0;
2335 	}
2336 
2337 	/* sort the pieces */
2338 	sort_pieces();
2339 
2340 	/* now read the artwork files */
2341 	for (piece = artwork_list; piece; piece = piece->next)
2342 	{
2343 		/* convert from pixel coordinates if necessary */
2344 		if (fabs(piece->left) > 4.0 || fabs(piece->right) > 4.0 ||
2345 			fabs(piece->top) > 4.0 || fabs(piece->bottom) > 4.0)
2346 		{
2347 			piece->left /= (double)width;
2348 			piece->right /= (double)width;
2349 			piece->top /= (double)height;
2350 			piece->bottom /= (double)height;
2351 		}
2352 
2353 		/* assign to one of the categories */
2354 		if (piece->layer == LAYER_BACKDROP)
2355 			num_underlays++;
2356 		else if (piece->layer == LAYER_OVERLAY)
2357 			num_overlays++;
2358 		else if (piece->layer >= LAYER_BEZEL)
2359 			num_bezels++;
2360 
2361 		/* load the graphics */
2362 		if (driver)
2363 			load_bitmap(driver->name, piece);
2364 	}
2365 
2366 /*	fprintf(stderr, "backdrops=%d overlays=%d bezels=%d\n", num_underlays, num_overlays, num_bezels);*/
2367 
2368 	return 1;
2369 }
2370 
2371 
2372 
2373 /*-------------------------------------------------
2374 	open_and_read_png - open a PNG file, read it
2375 	in, and verify that we can do something with
2376 	it
2377 -------------------------------------------------*/
2378 
open_and_read_png(const char * gamename,const char * filename,struct png_info * png)2379 static int open_and_read_png(const char *gamename, const char *filename, struct png_info *png)
2380 {
2381 	int result;
2382 	mame_file *file;
2383 
2384 	/* open the file */
2385 	file = mame_fopen(gamename, filename, FILETYPE_ARTWORK, 0);
2386 	if (!file)
2387 		return 0;
2388 
2389 	/* read the PNG data */
2390 	result = png_read_file(file, png);
2391 	mame_fclose(file);
2392 	if (!result)
2393 		return 0;
2394 
2395 	/* verify we can handle this PNG */
2396 	if (png->bit_depth > 8)
2397 	{
2398 		log_cb(RETRO_LOG_ERROR, LOGPRE "Unsupported bit depth %d (8 bit max)\n", png->bit_depth);
2399 		free(png->image);
2400 		return 0;
2401 	}
2402 	if (png->interlace_method != 0)
2403 	{
2404 		log_cb(RETRO_LOG_ERROR, LOGPRE "Interlace unsupported\n");
2405 		free(png->image);
2406 		return 0;
2407 	}
2408 	if (png->color_type != 0 && png->color_type != 3 && png->color_type != 2 && png->color_type != 6)
2409 	{
2410 		log_cb(RETRO_LOG_ERROR, LOGPRE "Unsupported color type %d\n", png->color_type);
2411 		free(png->image);
2412 		return 0;
2413 	}
2414 
2415 	/* if less than 8 bits, upsample */
2416 	png_expand_buffer_8bit(png);
2417 	return 1;
2418 }
2419 
2420 
2421 
2422 /*-------------------------------------------------
2423 	load_bitmap - load the artwork into a bitmap
2424 -------------------------------------------------*/
2425 
load_bitmap(const char * gamename,struct artwork_piece * piece)2426 static int load_bitmap(const char *gamename, struct artwork_piece *piece)
2427 {
2428 	struct png_info png;
2429 	UINT8 *src;
2430 	int x, y;
2431 
2432 	/* if we already have a bitmap, don't bother trying to read a file */
2433 	if (piece->rawbitmap)
2434 		return 1;
2435 
2436 	/* open and read the main png file */
2437 	if (!open_and_read_png(gamename, piece->filename, &png))
2438 	{
2439 		log_cb(RETRO_LOG_ERROR, LOGPRE "Can't load PNG file: %s\n", piece->filename);
2440 		return 0;
2441 	}
2442 
2443 	/* allocate the rawbitmap and erase it */
2444 	piece->rawbitmap = auto_bitmap_alloc_depth(png.width, png.height, 32);
2445 	if (!piece->rawbitmap)
2446 		return 0;
2447 	fillbitmap(piece->rawbitmap, 0, NULL);
2448 
2449 	/* handle 8bpp palettized case */
2450 	if (png.color_type == 3)
2451 	{
2452 		/* loop over width/height */
2453 		src = png.image;
2454 		for (y = 0; y < png.height; y++)
2455 			for (x = 0; x < png.width; x++, src++)
2456 			{
2457 				/* determine alpha */
2458 				UINT8 alpha = (*src < png.num_trans) ? png.trans[*src] : 0xff;
2459 				if (alpha != 0xff)
2460 					piece->has_alpha = 1;
2461 
2462 				/* expand to 32bpp */
2463 				plot_pixel(piece->rawbitmap, x, y, MAKE_ARGB(alpha, png.palette[*src * 3], png.palette[*src * 3 + 1], png.palette[*src * 3 + 2]));
2464 			}
2465 
2466 		/* free memory for the palette */
2467 		free(png.palette);
2468 	}
2469 
2470 	/* handle 8bpp grayscale case */
2471 	else if (png.color_type == 0)
2472 	{
2473 		/* loop over width/height */
2474 		src = png.image;
2475 		for (y = 0; y < png.height; y++)
2476 			for (x = 0; x < png.width; x++, src++)
2477 				plot_pixel(piece->rawbitmap, x, y, MAKE_ARGB(0xff, *src, *src, *src));
2478 	}
2479 
2480 	/* handle 32bpp non-alpha case */
2481 	else if (png.color_type == 2)
2482 	{
2483 		/* loop over width/height */
2484 		src = png.image;
2485 		for (y = 0; y < png.height; y++)
2486 			for (x = 0; x < png.width; x++, src += 3)
2487 				plot_pixel(piece->rawbitmap, x, y, MAKE_ARGB(0xff, src[0], src[1], src[2]));
2488 	}
2489 
2490 	/* handle 32bpp alpha case */
2491 	else
2492 	{
2493 		/* loop over width/height */
2494 		src = png.image;
2495 		for (y = 0; y < png.height; y++)
2496 			for (x = 0; x < png.width; x++, src += 4)
2497 				plot_pixel(piece->rawbitmap, x, y, MAKE_ARGB(src[3], src[0], src[1], src[2]));
2498 		piece->has_alpha = 1;
2499 	}
2500 
2501 	/* free the raw image data and return after loading any alpha map */
2502 	free(png.image);
2503 	return load_alpha_bitmap(gamename, piece, &png);
2504 }
2505 
2506 
2507 
2508 /*-------------------------------------------------
2509 	load_alpha_bitmap - load the external alpha
2510 	mask
2511 -------------------------------------------------*/
2512 
load_alpha_bitmap(const char * gamename,struct artwork_piece * piece,const struct png_info * original)2513 static int load_alpha_bitmap(const char *gamename, struct artwork_piece *piece, const struct png_info *original)
2514 {
2515 	struct png_info png;
2516 	UINT8 *src;
2517 	int x, y;
2518 
2519 	/* if no file, we succeeded */
2520 	if (!piece->alpha_filename)
2521 		return 1;
2522 
2523 	/* open and read the alpha png file */
2524 	if (!open_and_read_png(gamename, piece->alpha_filename, &png))
2525 	{
2526 		log_cb(RETRO_LOG_ERROR, LOGPRE "Can't load PNG file: %s\n", piece->alpha_filename);
2527 		return 0;
2528 	}
2529 
2530 	/* must be the same size */
2531 	if (png.height != original->height || png.width != original->width)
2532 	{
2533 		log_cb(RETRO_LOG_ERROR, LOGPRE "Alpha PNG must match original's dimensions: %s\n", piece->alpha_filename);
2534 		return 0;
2535 	}
2536 
2537 	/* okay, we have alpha */
2538 	piece->has_alpha = 1;
2539 
2540 	/* handle 8bpp palettized case */
2541 	if (png.color_type == 3)
2542 	{
2543 		/* loop over width/height */
2544 		src = png.image;
2545 		for (y = 0; y < png.height; y++)
2546 			for (x = 0; x < png.width; x++, src++)
2547 			{
2548 				rgb_t pixel = read_pixel(piece->rawbitmap, x, y);
2549 				UINT8 alpha = compute_brightness(MAKE_RGB(png.palette[*src * 3], png.palette[*src * 3 + 1], png.palette[*src * 3 + 2]));
2550 				plot_pixel(piece->rawbitmap, x, y, MAKE_ARGB(alpha, RGB_RED(pixel), RGB_GREEN(pixel), RGB_BLUE(pixel)));
2551 			}
2552 
2553 		/* free memory for the palette */
2554 		free(png.palette);
2555 	}
2556 
2557 	/* handle 8bpp grayscale case */
2558 	else if (png.color_type == 0)
2559 	{
2560 		/* loop over width/height */
2561 		src = png.image;
2562 		for (y = 0; y < png.height; y++)
2563 			for (x = 0; x < png.width; x++, src++)
2564 			{
2565 				rgb_t pixel = read_pixel(piece->rawbitmap, x, y);
2566 				plot_pixel(piece->rawbitmap, x, y, MAKE_ARGB(*src, RGB_RED(pixel), RGB_GREEN(pixel), RGB_BLUE(pixel)));
2567 			}
2568 	}
2569 
2570 	/* handle 32bpp non-alpha case */
2571 	else if (png.color_type == 2)
2572 	{
2573 		/* loop over width/height */
2574 		src = png.image;
2575 		for (y = 0; y < png.height; y++)
2576 			for (x = 0; x < png.width; x++, src += 3)
2577 			{
2578 				rgb_t pixel = read_pixel(piece->rawbitmap, x, y);
2579 				UINT8 alpha = compute_brightness(MAKE_RGB(src[0], src[1], src[2]));
2580 				plot_pixel(piece->rawbitmap, x, y, MAKE_ARGB(alpha, RGB_RED(pixel), RGB_GREEN(pixel), RGB_BLUE(pixel)));
2581 			}
2582 	}
2583 
2584 	/* handle 32bpp alpha case */
2585 	else
2586 	{
2587 		/* loop over width/height */
2588 		src = png.image;
2589 		for (y = 0; y < png.height; y++)
2590 			for (x = 0; x < png.width; x++, src += 4)
2591 			{
2592 				rgb_t pixel = read_pixel(piece->rawbitmap, x, y);
2593 				UINT8 alpha = compute_brightness(MAKE_RGB(src[0], src[1], src[2]));
2594 				plot_pixel(piece->rawbitmap, x, y, MAKE_ARGB(alpha, RGB_RED(pixel), RGB_GREEN(pixel), RGB_BLUE(pixel)));
2595 			}
2596 	}
2597 
2598 	/* free the raw image data */
2599 	free(png.image);
2600 	return 1;
2601 }
2602 
2603 
2604 
2605 /*-------------------------------------------------
2606 	artwork_prep - prepare the artwork
2607 -------------------------------------------------*/
2608 
artwork_prep(void)2609 static int artwork_prep(void)
2610 {
2611 	struct artwork_piece *piece;
2612 
2613 	/* mark everything dirty */
2614 	underlay_invalid = screenrect;
2615 	overlay_invalid = screenrect;
2616 	bezel_invalid = screenrect;
2617 
2618 	/* loop through all the pieces, generating the scaled bitmaps */
2619 	for (piece = artwork_list; piece; piece = piece->next)
2620 	{
2621 		/* scale to the artwork's intended dimensions */
2622 		if (!scale_bitmap(piece, piece->bounds.max_x - piece->bounds.min_x + 1, piece->bounds.max_y - piece->bounds.min_y + 1))
2623 			return 1;
2624 
2625 		/* trim the bitmap down if transparent */
2626 		trim_bitmap(piece);
2627 
2628 		/* do we intersect the game rect? */
2629 		piece->intersects_game = 0;
2630 		if (piece->bounds.max_x > gamerect.min_x && piece->bounds.min_x < gamerect.max_x &&
2631 			piece->bounds.max_y > gamerect.min_y && piece->bounds.min_y < gamerect.max_y)
2632 			piece->intersects_game = 1;
2633 	}
2634 	return 0;
2635 }
2636 
2637 
2638 
2639 /*-------------------------------------------------
2640 	scale_bitmap - scale the bitmap for a
2641 	given piece of artwork
2642 -------------------------------------------------*/
2643 
scale_bitmap(struct artwork_piece * piece,int newwidth,int newheight)2644 static int scale_bitmap(struct artwork_piece *piece, int newwidth, int newheight)
2645 {
2646 	UINT32 global_brightness, global_alpha;
2647 	UINT64 sumscale;
2648 	UINT32 dx, dy;
2649 	int x, y;
2650 
2651 	/* skip if no bitmap */
2652 	if (!piece->rawbitmap)
2653 		return 1;
2654 
2655 	/* allocate two new bitmaps */
2656 	piece->prebitmap = auto_bitmap_alloc_depth(newwidth, newheight, -32);
2657 	piece->yrgbbitmap = auto_bitmap_alloc_depth(newwidth, newheight, -32);
2658 	if (!piece->prebitmap || !piece->yrgbbitmap)
2659 		return 0;
2660 
2661 	/* also allocate memory for the scanline hints */
2662 	piece->scanlinehint = auto_malloc(newheight * MAX_HINTS_PER_SCANLINE * sizeof(piece->scanlinehint[0]));
2663 	memset(piece->scanlinehint, 0, newheight * MAX_HINTS_PER_SCANLINE * sizeof(piece->scanlinehint[0]));
2664 
2665 	/* convert global brightness and alpha to fixed point */
2666 	global_brightness = (int)(piece->brightness * 65536.0);
2667 	global_alpha = (int)(piece->alpha * 65536.0);
2668 
2669 	/* compute parameters for scaling */
2670 	dx = (piece->rawbitmap->width << 12) / newwidth;
2671 	dy = (piece->rawbitmap->height << 12) / newheight;
2672 	sumscale = (UINT64)dx * (UINT64)dy;
2673 
2674 	/* loop over the target vertically */
2675 	for (y = 0; y < newheight; y++)
2676 	{
2677 		int prevstate = 0, statex = 0;
2678 		int newstate;
2679 
2680 		UINT32 starty = y * dy;
2681 
2682 		/* loop over the target horizontally */
2683 		for (x = 0; x < newwidth; x++)
2684 		{
2685 			UINT32 startx = x * dx;
2686 			UINT32 a, r, g, b;
2687 
2688 			/* if the source is higher res than the target, use full averaging */
2689 			if (dx > 0x1000 || dy > 0x1000)
2690 			{
2691 				UINT64 sumr = 0, sumg = 0, sumb = 0, suma = 0;
2692 				UINT32 xchunk, ychunk;
2693 				UINT32 curx, cury;
2694 
2695 				UINT32 yremaining = dy;
2696 
2697 				/* accumulate all source pixels that contribute to this pixel */
2698 				for (cury = starty; yremaining; cury += ychunk)
2699 				{
2700 					UINT32 xremaining = dx;
2701 
2702 					/* determine the Y contribution, clamping to the amount remaining */
2703 					ychunk = 0x1000 - (cury & 0xfff);
2704 					if (ychunk > yremaining)
2705 						ychunk = yremaining;
2706 					yremaining -= ychunk;
2707 
2708 					/* loop over all source pixels in the X direction */
2709 					for (curx = startx; xremaining; curx += xchunk)
2710 					{
2711 						UINT32 factor;
2712 						UINT32 pix;
2713 
2714 						/* determine the X contribution, clamping to the amount remaining */
2715 						xchunk = 0x1000 - (curx & 0xfff);
2716 						if (xchunk > xremaining)
2717 							xchunk = xremaining;
2718 						xremaining -= xchunk;
2719 
2720 						/* total contribution = x * y */
2721 						factor = xchunk * ychunk;
2722 
2723 						/* fetch the source pixel */
2724 						pix = ((UINT32 *)piece->rawbitmap->line[cury >> 12])[curx >> 12];
2725 
2726 						/* accumulate the RGBA values */
2727 						sumr += factor * RGB_RED(pix);
2728 						sumg += factor * RGB_GREEN(pix);
2729 						sumb += factor * RGB_BLUE(pix);
2730 						suma += factor * RGB_ALPHA(pix);
2731 					}
2732 				}
2733 
2734 				/* apply final scale */
2735 				a = suma / sumscale;
2736 				r = sumr / sumscale;
2737 				g = sumg / sumscale;
2738 				b = sumb / sumscale;
2739 			}
2740 
2741 			/* otherwise, use bilinear filtering to scale up */
2742 			else
2743 			{
2744 				UINT32 pix0, pix1, pix2, pix3;
2745 				UINT32 sumr, sumg, sumb, suma;
2746 				UINT32 nextx, nexty;
2747 				UINT32 curx, cury;
2748 				UINT32 factor;
2749 
2750 				/* adjust start to the center */
2751 				curx = startx + dx / 2 - 0x800;
2752 				cury = starty + dy / 2 - 0x800;
2753 
2754 				/* compute the neighboring pixel */
2755 				nextx = curx + 0x1000;
2756 				nexty = cury + 0x1000;
2757 
2758 				/* clamp start */
2759 				if ((INT32)curx < 0) curx += 0x1000;
2760 				if ((INT32)cury < 0) cury += 0x1000;
2761 
2762 				/* fetch the four relevant pixels */
2763 				pix0 = ((UINT32 *)piece->rawbitmap->line[cury >> 12])[curx >> 12];
2764 				pix1 = ((UINT32 *)piece->rawbitmap->line[cury >> 12])[nextx >> 12];
2765 				pix2 = ((UINT32 *)piece->rawbitmap->line[nexty >> 12])[curx >> 12];
2766 				pix3 = ((UINT32 *)piece->rawbitmap->line[nexty >> 12])[nextx >> 12];
2767 
2768 				/* compute the x/y scaling factors */
2769 				curx &= 0xfff;
2770 				cury &= 0xfff;
2771 
2772 				/* contributions from pixel 0 (top,left) */
2773 				factor = (0x1000 - curx) * (0x1000 - cury);
2774 				sumr = factor * RGB_RED(pix0);
2775 				sumg = factor * RGB_GREEN(pix0);
2776 				sumb = factor * RGB_BLUE(pix0);
2777 				suma = factor * RGB_ALPHA(pix0);
2778 
2779 				/* contributions from pixel 1 (top,right) */
2780 				factor = curx * (0x1000 - cury);
2781 				sumr += factor * RGB_RED(pix1);
2782 				sumg += factor * RGB_GREEN(pix1);
2783 				sumb += factor * RGB_BLUE(pix1);
2784 				suma += factor * RGB_ALPHA(pix1);
2785 
2786 				/* contributions from pixel 2 (bottom,left) */
2787 				factor = (0x1000 - curx) * cury;
2788 				sumr += factor * RGB_RED(pix2);
2789 				sumg += factor * RGB_GREEN(pix2);
2790 				sumb += factor * RGB_BLUE(pix2);
2791 				suma += factor * RGB_ALPHA(pix2);
2792 
2793 				/* contributions from pixel 3 (bottom,right) */
2794 				factor = curx * cury;
2795 				sumr += factor * RGB_RED(pix3);
2796 				sumg += factor * RGB_GREEN(pix3);
2797 				sumb += factor * RGB_BLUE(pix3);
2798 				suma += factor * RGB_ALPHA(pix3);
2799 
2800 				/* apply final scale */
2801 				r = sumr >> 24;
2802 				g = sumg >> 24;
2803 				b = sumb >> 24;
2804 				a = suma >> 24;
2805 			}
2806 
2807 			/* apply alpha and brightness */
2808 			a = (a * global_alpha) >> 16;
2809 			r = (r * global_brightness) >> 16;
2810 			g = (g * global_brightness) >> 16;
2811 			b = (b * global_brightness) >> 16;
2812 
2813 			/* store to both bitmaps */
2814 			*((UINT32 *)piece->prebitmap->base + y * piece->prebitmap->rowpixels + x) = compute_pre_pixel(a,r,g,b);
2815 			*((UINT32 *)piece->yrgbbitmap->base + y * piece->yrgbbitmap->rowpixels + x) = compute_yrgb_pixel(a,r,g,b);
2816 
2817 			/* look for state changes */
2818 			newstate = (a != 0);
2819 			if (newstate != prevstate)
2820 			{
2821 				prevstate = newstate;
2822 
2823 				/* if starting a new run of non-transparent pixels, remember the start point */
2824 				if (newstate)
2825 					statex = x;
2826 
2827 				/* otherwise, add the current run */
2828 				else
2829 					add_range_to_hint(piece->scanlinehint, y, statex, x - 1);
2830 			}
2831 		}
2832 
2833 		/* add the final range */
2834 		if (prevstate)
2835 			add_range_to_hint(piece->scanlinehint, y, statex, x - 1);
2836 	}
2837 
2838 	/* guess it worked! */
2839 return 1;
2840 }
2841 
2842 
2843 
2844 /*-------------------------------------------------
2845 	trim_bitmap - remove any transparent borders
2846 	from a scaled image
2847 -------------------------------------------------*/
2848 
trim_bitmap(struct artwork_piece * piece)2849 static void trim_bitmap(struct artwork_piece *piece)
2850 {
2851 	UINT32 *hintbase = piece->scanlinehint;
2852 	int top, bottom, left, right;
2853 	int x, y, height, width;
2854 
2855 	/* skip if no bitmap */
2856 	if (!piece->rawbitmap)
2857 		return;
2858 
2859 	/* don't trim overlay bitmaps */
2860 	if (piece->layer == LAYER_OVERLAY)
2861 		return;
2862 
2863 	/* scan from the top down, looking for empty rows */
2864 	height = piece->prebitmap->height;
2865 	width = piece->prebitmap->width;
2866 	for (top = 0; top < height; top++)
2867 		if (hintbase[top * MAX_HINTS_PER_SCANLINE] != 0)
2868 			break;
2869 
2870 	/* scan from the bottom up, looking for empty rows */
2871 	for (bottom = height - 1; bottom >= top; bottom--)
2872 		if (hintbase[bottom * MAX_HINTS_PER_SCANLINE] != 0)
2873 			break;
2874 
2875 	/* now find the min/max */
2876 	left = width - 1;
2877 	right = 0;
2878 	for (y = top; y <= bottom; y++)
2879 	{
2880 		const UINT32 *hintdata = &hintbase[y * MAX_HINTS_PER_SCANLINE];
2881 
2882 		/* check the minimum against the left */
2883 		if (hintdata[0] && (hintdata[0] >> 16) < left)
2884 			left = hintdata[0] >> 16;
2885 
2886 		/* find the maximum */
2887 		for (x = 0; x < MAX_HINTS_PER_SCANLINE; x++)
2888 			if (hintdata[x] && (hintdata[x] & 0xffff) > right)
2889 				right = hintdata[x] & 0xffff;
2890 	}
2891 
2892 	logerror("Trimming bitmap from (%d,%d)-(%d,%d) to (%d,%d)-(%d,%d)\n",
2893 			piece->bounds.min_x, piece->bounds.min_y, piece->bounds.max_x, piece->bounds.max_y,
2894 			piece->bounds.min_x + left, piece->bounds.min_y + top, piece->bounds.min_x + right, piece->bounds.min_y + bottom);
2895 
2896 	/* skip if all is normal */
2897 	if (left == 0 && top == 0 && right == width - 1 && bottom == height - 1)
2898 		return;
2899 
2900 	/* now shift the bitmap data */
2901 	for (y = top; y <= bottom; y++)
2902 	{
2903 		UINT32 *hintsrc = &hintbase[y * MAX_HINTS_PER_SCANLINE];
2904 		UINT32 *hintdst = &hintbase[(y - top) * MAX_HINTS_PER_SCANLINE];
2905 		UINT32 *dst1 = (UINT32 *)piece->prebitmap->base + (y - top) * piece->prebitmap->rowpixels;
2906 		UINT32 *dst2 = (UINT32 *)piece->yrgbbitmap->base + (y - top) * piece->yrgbbitmap->rowpixels;
2907 		UINT32 *src1 = (UINT32 *)piece->prebitmap->base + y * piece->prebitmap->rowpixels + left;
2908 		UINT32 *src2 = (UINT32 *)piece->yrgbbitmap->base + y * piece->yrgbbitmap->rowpixels + left;
2909 
2910 		memmove(dst1, src1, (right - left + 1) * sizeof(UINT32));
2911 		memmove(dst2, src2, (right - left + 1) * sizeof(UINT32));
2912 
2913 		/* adjust the hints */
2914 		for (x = 0; x < MAX_HINTS_PER_SCANLINE; x++)
2915 		{
2916 			UINT32 data = hintsrc[x];
2917 			if (data)
2918 				data -= (left << 16) | left;
2919 			hintdst[x] = data;
2920 		}
2921 	}
2922 
2923 	/* and adjust the info */
2924 	piece->bounds.max_x = piece->bounds.min_x + right;
2925 	piece->bounds.min_x += left;
2926 	piece->bounds.max_y = piece->bounds.min_y + bottom;
2927 	piece->bounds.min_y += top;
2928 }
2929 
2930 
2931 
2932 
2933 #if 0
2934 #pragma mark -
2935 #pragma mark PIECE LIST MANAGEMENT
2936 #endif
2937 
2938 /*-------------------------------------------------
2939 	create_new_piece - allocate a new piece
2940 	entry
2941 -------------------------------------------------*/
2942 
create_new_piece(const char * tag)2943 static struct artwork_piece *create_new_piece(const char *tag)
2944 {
2945 	/* allocate a new piece */
2946 	struct artwork_piece *newpiece = auto_malloc(sizeof(struct artwork_piece));
2947 	num_pieces++;
2948 
2949 	/* initialize to default values */
2950 	memset(newpiece, 0, sizeof(*newpiece));
2951 	newpiece->layer = LAYER_UNKNOWN;
2952 	newpiece->has_alpha = 0;
2953 	newpiece->priority = 0;
2954 	newpiece->alpha = 1.0;
2955 	newpiece->brightness = 1.0;
2956 	newpiece->filename = NULL;
2957 	newpiece->alpha_filename = NULL;
2958 	newpiece->intersects_game = 0;
2959 	newpiece->visible = 1;
2960 
2961 	/* allocate space for the filename */
2962 	newpiece->tag = auto_malloc(strlen(tag) + 1);
2963 	strcpy(newpiece->tag, tag);
2964 
2965 	/* link into the list */
2966 	newpiece->next = artwork_list;
2967 	artwork_list = newpiece;
2968 	return newpiece;
2969 }
2970 
2971 
2972 
2973 /*-------------------------------------------------
2974 	artwork_sort_compare - qsort compare function
2975 	to sort pieces by priority
2976 -------------------------------------------------*/
2977 
artwork_sort_compare(const void * item1,const void * item2)2978 static int CLIB_DECL artwork_sort_compare(const void *item1, const void *item2)
2979 {
2980 	const struct artwork_piece *piece1 = *((const struct artwork_piece **)item1);
2981 	const struct artwork_piece *piece2 = *((const struct artwork_piece **)item2);
2982 	if (piece1->layer < piece2->layer)
2983 		return -1;
2984 	else if (piece1->layer > piece2->layer)
2985 		return 1;
2986 	else if (piece1->priority < piece2->priority)
2987 		return -1;
2988 	else if (piece1->priority > piece2->priority)
2989 		return 1;
2990 	else
2991 		return 0;
2992 }
2993 
2994 
2995 
2996 /*-------------------------------------------------
2997 	sort_pieces - sort the pieces by priority
2998 -------------------------------------------------*/
2999 
sort_pieces(void)3000 static void sort_pieces(void)
3001 {
3002 	struct artwork_piece *array[MAX_PIECES];
3003 	struct artwork_piece *piece;
3004 	int i = 0;
3005 
3006 	/* copy the list into the array, filtering as we go */
3007 	for (piece = artwork_list; piece; piece = piece->next)
3008 	{
3009 		switch (piece->layer)
3010 		{
3011 			case LAYER_BACKDROP:
3012 				if (options.use_artwork & ARTWORK_USE_BACKDROPS)
3013 					array[i++] = piece;
3014 				break;
3015 
3016 			case LAYER_OVERLAY:
3017 				if (options.use_artwork & ARTWORK_USE_OVERLAYS)
3018 					array[i++] = piece;
3019 				break;
3020 
3021 			default:
3022 				if (options.use_artwork & ARTWORK_USE_BEZELS)
3023 					array[i++] = piece;
3024 				break;
3025 		}
3026 	}
3027 	num_pieces = i;
3028 	if (num_pieces == 0)
3029 	{
3030 		artwork_list = NULL;
3031 		return;
3032 	}
3033 
3034 	/* now sort it */
3035 	if (num_pieces > 1)
3036 		qsort(array, num_pieces, sizeof(array[0]), artwork_sort_compare);
3037 
3038 	/* now reassemble the list */
3039 	artwork_list = piece = array[0];
3040 	for (i = 1; i < num_pieces; i++)
3041 	{
3042 		piece->next = array[i];
3043 		piece = piece->next;
3044 	}
3045 	piece->next = NULL;
3046 }
3047 
3048 
3049 
3050 /*-------------------------------------------------
3051 	validate_pieces - make sure we got valid data
3052 -------------------------------------------------*/
3053 
validate_pieces(void)3054 static int validate_pieces(void)
3055 {
3056 	struct artwork_piece *piece;
3057 
3058 	/* verify each one */
3059 	for (piece = artwork_list; piece; piece = piece->next)
3060 	{
3061 		/* make sure we have a filename */
3062 		if ((!piece->filename || strlen(piece->filename) == 0) && !piece->rawbitmap)
3063 		{
3064 			log_cb(RETRO_LOG_ERROR, LOGPRE "Artwork piece '%s' has no file!\n", piece->tag);
3065 			return 0;
3066 		}
3067 
3068 		/* make sure we have a layer */
3069 		if (piece->layer == LAYER_UNKNOWN)
3070 		{
3071 			log_cb(RETRO_LOG_ERROR, LOGPRE "Artwork piece '%s' has no layer!\n", piece->tag);
3072 			return 0;
3073 		}
3074 
3075 		/* make sure we have a position */
3076 		if (piece->left == 0 && piece->right == 0)
3077 		{
3078 			log_cb(RETRO_LOG_ERROR, LOGPRE "Artwork piece '%s' has no position!\n", piece->tag);
3079 			return 0;
3080 		}
3081 
3082 		/* make sure the position is valid */
3083 		if (piece->left >= piece->right || piece->top >= piece->bottom)
3084 		{
3085 			log_cb(RETRO_LOG_ERROR, LOGPRE "Artwork piece '%s' has invalid position data!\n", piece->tag);
3086 			return 0;
3087 		}
3088 	}
3089 
3090 	return 1;
3091 }
3092 
3093 
3094 
3095 #if 0
3096 #pragma mark -
3097 #pragma mark OVERLAY GENERATION
3098 #endif
3099 
3100 /*-------------------------------------------------
3101 	generate_rect_piece - generate a rectangular
3102 	overlay piece
3103 -------------------------------------------------*/
3104 
generate_rect_piece(struct artwork_piece * piece,const struct overlay_piece * data,int width,int height)3105 static int generate_rect_piece(struct artwork_piece *piece, const struct overlay_piece *data, int width, int height)
3106 {
3107 	int gfxwidth, gfxheight;
3108 
3109 	/* extract coordinates */
3110 	piece->top = data->top;
3111 	piece->left = data->left;
3112 	piece->bottom = data->bottom;
3113 	piece->right = data->right;
3114 
3115 	/* convert from pixel coordinates if necessary */
3116 	if (fabs(piece->left) > 4.0 || fabs(piece->right) > 4.0 ||
3117 		fabs(piece->top) > 4.0 || fabs(piece->bottom) > 4.0)
3118 	{
3119 		piece->left /= (double)width;
3120 		piece->right /= (double)width;
3121 		piece->top /= (double)height;
3122 		piece->bottom /= (double)height;
3123 	}
3124 
3125 	/* compute the effective width/height */
3126 	gfxwidth = (int)((piece->right - piece->left) * (double)width * 2.0 + 0.5);
3127 	gfxheight = (int)((piece->bottom - piece->top) * (double)height * 2.0 + 0.5);
3128 
3129 	/* allocate a source bitmap 2x the game bitmap's size */
3130 	piece->rawbitmap = auto_bitmap_alloc_depth(gfxwidth, gfxheight, 32);
3131 	if (!piece->rawbitmap)
3132 		return 0;
3133 
3134 	/* fill the bitmap */
3135 	fillbitmap(piece->rawbitmap, data->color, NULL);
3136 	return 1;
3137 }
3138 
3139 
3140 
3141 /*-------------------------------------------------
3142 	generate_disk_piece - generate a disk-shaped
3143 	overlay piece
3144 -------------------------------------------------*/
3145 
render_disk(struct mame_bitmap * bitmap,int r,UINT32 color)3146 static void render_disk(struct mame_bitmap *bitmap, int r, UINT32 color)
3147 {
3148 	int xc = bitmap->width / 2, yc = bitmap->height / 2;
3149 	int x = 0, twox = 0;
3150 	int y = r;
3151 	int twoy = r+r;
3152 	int p = 1 - r;
3153 	int i;
3154 
3155 	while (x < y)
3156 	{
3157 		x++;
3158 		twox +=2;
3159 		if (p < 0)
3160 			p += twox + 1;
3161 		else
3162 		{
3163 			y--;
3164 			twoy -= 2;
3165 			p += twox - twoy + 1;
3166 		}
3167 
3168 		for (i = 0; i < twox; i++)
3169 		{
3170 			plot_pixel(bitmap, xc-x+i, yc-y, color);
3171 			plot_pixel(bitmap, xc-x+i, yc+y-1, color);
3172 		}
3173 
3174 		for (i = 0; i < twoy; i++)
3175 		{
3176 			plot_pixel(bitmap, xc-y+i, yc-x, color);
3177 			plot_pixel(bitmap, xc-y+i, yc+x-1, color);
3178 		}
3179 	}
3180 }
3181 
3182 
generate_disk_piece(struct artwork_piece * piece,const struct overlay_piece * data,int width,int height)3183 static int generate_disk_piece(struct artwork_piece *piece, const struct overlay_piece *data, int width, int height)
3184 {
3185 	double x = data->left, y = data->top, r = data->right;
3186 	struct rectangle temprect;
3187 	int gfxwidth, gfxradius;
3188 
3189 	/* convert from pixel coordinates if necessary */
3190 	if (fabs(x) > 4.0 || fabs(y) > 4.0 || fabs(r) > 4.0)
3191 	{
3192 		x /= (double)width;
3193 		y /= (double)height;
3194 		r /= (double)width;
3195 	}
3196 
3197 	/* generate coordinates */
3198 	piece->top = y - r * (double)width / (double)height;
3199 	piece->left = x - r;
3200 	piece->bottom = y + r * (double)width / (double)height;
3201 	piece->right = x + r;
3202 
3203 	/* compute the effective width/height */
3204 	gfxwidth = (int)((piece->right - piece->left) * (double)width * 2.0 + 0.5);
3205 	gfxradius = (int)(r * (double)width * 2.0 + 0.5);
3206 
3207 	/* allocate a source bitmap 2x the game bitmap's size */
3208 	piece->rawbitmap = auto_bitmap_alloc_depth(gfxwidth, gfxwidth, 32);
3209 	if (!piece->rawbitmap)
3210 		return 0;
3211 
3212 	/* fill the bitmap with white */
3213 	temprect.min_x = temprect.min_y = 0;
3214 	temprect.max_x = piece->rawbitmap->width - 1;
3215 	temprect.max_y = piece->rawbitmap->height - 1;
3216 	erase_rect(piece->rawbitmap, &temprect, MAKE_ARGB(0,0xff,0xff,0xff));
3217 
3218 	/* now render the disk */
3219 	render_disk(piece->rawbitmap, gfxradius, data->color);
3220 	return 1;
3221 }
3222 
3223 
3224 /****************************************************************************
3225 Renders the right angled triangle. If upper is true, the upper half of
3226 the triangle is filled, otherwise the lower half is filled. If reverse is
3227 true, the gradient of the triangle is positive, otherwise negative.
3228 ****************************************************************************/
render_right_triangle(struct mame_bitmap * bitmap,int reverse,int upper,UINT32 color)3229 static void render_right_triangle(struct mame_bitmap *bitmap, int reverse, int upper, UINT32 color)
3230 {
3231     if (reverse) {
3232 	int j;
3233 	for (j = 0; j < bitmap->height; j++)
3234 	    if (upper) {
3235 		int i;
3236 		for (i = 0; i <= ((double) bitmap->width / (double) bitmap->height)*j; i++)
3237 		    plot_pixel(bitmap, i, bitmap->height-j-1, color);
3238 	    } else {
3239 		int i;
3240 		for (i = ((double) bitmap->width / (double) bitmap->height)*j; i < bitmap->width; i++)
3241 		    plot_pixel(bitmap, i, bitmap->height-j-1, color);
3242 	    }
3243     } else {
3244 	int j;
3245 	for (j = 0; j < bitmap->height; j++) {
3246 	    if (upper) {
3247 		int i;
3248 	 	for (i = ((double) bitmap->width / (double) bitmap->height)*j; i < bitmap->width; i++)
3249 		    plot_pixel(bitmap, i, j, color);
3250 	    } else {
3251 		int i;
3252 		for (i = 0; i <= ((double) bitmap->width / (double) bitmap->height)*j; i++)
3253 		    plot_pixel(bitmap, i, j, color);
3254 	    }
3255 	}
3256     }
3257 }
3258 
3259 
3260 /****************************************************************************
3261 Generates a right angled triangle.
3262 Coordinates of the piece are labelled internal as (left,top), (right,bottom)
3263 however, these represent (x,y) and (z,w) in the following situations:
3264 
3265 (x,y)                     (z,w)
3266      X                         X********
3267      ***                         *******
3268      *****                         *****
3269      *******                         ***
3270      ********X                         X
3271               (z,w)                     (x,y)
3272 
3273               (z,w)                     (x,y)
3274              X                 ********X
3275            ***                 *******
3276          *****                 *****
3277        *******                 ***
3278      X********                 X
3279 (x,y)                     (z,w)
3280 
3281 As such, we must rearrange the coordinates to not upset the drawing code
3282 that expects (left,top) and (right, bottom).
3283 ****************************************************************************/
generate_right_triangle_piece(struct artwork_piece * piece,const struct overlay_piece * data,int width,int height)3284 static int generate_right_triangle_piece(struct artwork_piece *piece, const struct overlay_piece *data, int width, int height)
3285 {
3286 	int reverse, upper;
3287 	int gfxwidth, gfxheight;
3288 	struct rectangle temprect;
3289 
3290 	/* extract coordinates */
3291 	piece->top = data->top;
3292 	piece->left = data->left;
3293 	piece->bottom = data->bottom;
3294 	piece->right = data->right;
3295 
3296 	/* convert from pixel coordinates if necessary */
3297 	if (fabs(piece->left) > 4.0 || fabs(piece->right) > 4.0 ||
3298 		fabs(piece->top) > 4.0 || fabs(piece->bottom) > 4.0)
3299 	{
3300 		piece->left /= (double)width;
3301 		piece->right /= (double)width;
3302 		piece->top /= (double)height;
3303 		piece->bottom /= (double)height;
3304 	}
3305 
3306 	/* compute the effective width/height */
3307 	gfxwidth = (int)(fabs(piece->right - piece->left) * (double)width * 2.0 + 0.5);
3308 	gfxheight = (int)(fabs(piece->bottom - piece->top) * (double)height * 2.0 + 0.5);
3309 
3310 	/* allocate a source bitmap 2x the game bitmap's size */
3311 	piece->rawbitmap = auto_bitmap_alloc_depth(gfxwidth, gfxheight, 32);
3312 	if (!piece->rawbitmap)
3313 		return 0;
3314 
3315 	/* fill the bitmap with white */
3316 	temprect.min_x = temprect.min_y = 0;
3317 	temprect.max_x = piece->rawbitmap->width - 1;
3318 	temprect.max_y = piece->rawbitmap->height - 1;
3319 	erase_rect(piece->rawbitmap, &temprect, MAKE_ARGB(0,0xff,0xff,0xff));
3320 
3321 	/* work out rules for upper and reverse used in drawing the right shape */
3322 	reverse = (piece->left < piece->right && piece->top > piece->bottom)
3323 	    || (piece->left > piece->right && piece->top < piece->bottom);
3324 	upper = piece->left > piece->right;
3325 
3326 	/* Get the coordinates back to the drawing code expectation that */
3327 	/* (left, top) is top left, and (right, bottom) is bottom right */
3328 	if (piece->right < piece->left) {
3329 	    double temp = piece->left;
3330 	    piece->left = piece->right;
3331 	    piece->right = temp;
3332 	}
3333 	if (piece->bottom < piece->top) {
3334 	    double temp = piece->top;
3335 	    piece->top = piece->bottom;
3336 	    piece->bottom = temp;
3337 	}
3338 
3339 	/* now render the triangle */
3340 	render_right_triangle(piece->rawbitmap, reverse, upper, data->color);
3341 	return 1;
3342 }
3343 
3344 
3345 
3346 /*-------------------------------------------------
3347 	generate_overlay - generate an overlay with
3348 	the given pieces
3349 -------------------------------------------------*/
3350 
generate_overlay(const struct overlay_piece * list,int width,int height)3351 static int generate_overlay(const struct overlay_piece *list, int width, int height)
3352 {
3353 	struct artwork_piece *piece;
3354 	int priority = 0;
3355 
3356 	/* loop until done */
3357 	while (list->type != OVERLAY_TYPE_END)
3358 	{
3359 		/* first create a new piece to use */
3360 		piece = create_new_piece(OVERLAY_TAG);
3361 		if (!piece)
3362 			return 0;
3363 
3364 		/* fill in the basics */
3365 		piece->has_alpha = 1;
3366 		piece->layer = LAYER_OVERLAY;
3367 		piece->priority = priority++;
3368 		piece->blendflags = list->type & OVERLAY_FLAG_MASK;
3369 		piece->tag = list->tag; // Handle someone using a different tag, for example, cocktail mode
3370 
3371 		/* switch off the type */
3372 		switch (list->type & ~OVERLAY_FLAG_MASK)
3373 		{
3374 			case OVERLAY_TYPE_RECTANGLE:
3375 				if (!generate_rect_piece(piece, list, width, height))
3376 					return 0;
3377 				break;
3378 
3379 			case OVERLAY_TYPE_DISK:
3380 				if (!generate_disk_piece(piece, list, width, height))
3381 					return 0;
3382 				break;
3383 			case OVERLAY_TYPE_RIGHT_TRIANGLE:
3384 				if (!generate_right_triangle_piece(piece, list, width, height))
3385 					return 0;
3386 				break;
3387 		}
3388 
3389 		/* next */
3390 		list++;
3391 	}
3392 
3393 	return 1;
3394 }
3395 
3396 
3397 
3398 #if 0
3399 #pragma mark -
3400 #pragma mark ART FILE PARSING
3401 #endif
3402 
3403 /*-------------------------------------------------
3404 	strip_space - strip leading/trailing spaces
3405 -------------------------------------------------*/
3406 
strip_space(char * string)3407 static char *strip_space(char *string)
3408 {
3409 	char *start, *end;
3410 
3411 	/* skip over leading space */
3412 	for (start = string; *start && isspace(*start); start++) ;
3413 
3414 	/* NULL terminate over trailing space */
3415 	for (end = start + strlen(start) - 1; end > start && isspace(*end); end--) *end = 0;
3416 	return start;
3417 }
3418 
3419 
3420 
3421 /*-------------------------------------------------
3422 	parse_tag_value - parse a tag/value pair
3423 -------------------------------------------------*/
3424 
parse_tag_value(struct artwork_piece * piece,const char * tag,const char * value)3425 static int parse_tag_value(struct artwork_piece *piece, const char *tag, const char *value)
3426 {
3427 	/* handle the various tags */
3428 	if (!strcmp(tag, "layer"))
3429 	{
3430 		if (!strcmp(value, "backdrop"))
3431 			piece->layer = LAYER_BACKDROP;
3432 		else if (!strcmp(value, "overlay"))
3433 			piece->layer = LAYER_OVERLAY;
3434 		else if (!strcmp(value, "bezel"))
3435 			piece->layer = LAYER_BEZEL;
3436 		else if (!strcmp(value, "marquee"))
3437 			piece->layer = LAYER_MARQUEE;
3438 		else if (!strcmp(value, "panel"))
3439 			piece->layer = LAYER_PANEL;
3440 		else if (!strcmp(value, "side"))
3441 			piece->layer = LAYER_SIDE;
3442 		else if (!strcmp(value, "flyer"))
3443 			piece->layer = LAYER_FLYER;
3444 		else
3445 			return 0;
3446 		return 1;
3447 	}
3448 	else if (!strcmp(tag, "priority"))
3449 	{
3450 		return (sscanf(value, "%d", &piece->priority) == 1);
3451 	}
3452 	else if (!strcmp(tag, "visible"))
3453 	{
3454 		return (sscanf(value, "%d", &piece->visible) == 1);
3455 	}
3456 	else if (!strcmp(tag, "alpha"))
3457 	{
3458 		return (sscanf(value, "%f", &piece->alpha) == 1);
3459 	}
3460 	else if (!strcmp(tag, "brightness"))
3461 	{
3462 		return (sscanf(value, "%f", &piece->brightness) == 1);
3463 	}
3464 	else if (!strcmp(tag, "position"))
3465 	{
3466 		return (sscanf(value, "%f,%f,%f,%f", &piece->left, &piece->top, &piece->right, &piece->bottom) == 4);
3467 	}
3468 	else if (!strcmp(tag, "file"))
3469 	{
3470 		piece->filename = auto_malloc(strlen(value) + 1);
3471 		strcpy(piece->filename, value);
3472 		return (piece->filename != NULL);
3473 	}
3474 	else if (!strcmp(tag, "alphafile"))
3475 	{
3476 		piece->alpha_filename = auto_malloc(strlen(value) + 1);
3477 		strcpy(piece->alpha_filename, value);
3478 		return (piece->alpha_filename != NULL);
3479 	}
3480 	return 0;
3481 }
3482 
3483 
3484 
3485 /*-------------------------------------------------
3486 	parse_art_file - parse a .art file
3487 -------------------------------------------------*/
3488 
parse_art_file(mame_file * file)3489 static int parse_art_file(mame_file *file)
3490 {
3491 	struct artwork_piece *current = NULL;
3492 	char *tag, *value, *p;
3493 	char buffer[1000];
3494 
3495 	/* loop until we run out of lines */
3496 	while (mame_fgets(buffer, sizeof(buffer), file))
3497 	{
3498 		/* strip off any comments */
3499 		p = strstr(buffer, "//");
3500 		if (p)
3501 			*p = 0;
3502 
3503 		/* strip off leading/trailing spaces */
3504 		tag = strip_space(buffer);
3505 
3506 		/* anything left? */
3507 		if (tag[0] == 0)
3508 			continue;
3509 
3510 		/* is this the start of a new entry? */
3511 		if (tag[strlen(tag) - 1] == ':')
3512 		{
3513 			/* strip the space off the rest */
3514 			tag[strlen(tag) - 1] = 0;
3515 			tag = strip_space(tag);
3516 
3517 			/* create an entry for the new piece */
3518 			current = create_new_piece(tag);
3519 			if (!current)
3520 				return 0;
3521 			continue;
3522 		}
3523 
3524 		/* is this a tag/value pair? */
3525 		value = strchr(tag, '=');
3526 		if (value)
3527 		{
3528 			/* strip spaces off of both parts */
3529 			*value++ = 0;
3530 			tag = strip_space(tag);
3531 			value = strip_space(value);
3532 
3533 			/* convert both strings to lowercase */
3534 			for (p = tag; *p; p++) *p = tolower(*p);
3535 			for (p = value; *p; p++) *p = tolower(*p);
3536 
3537 			/* now parse the result */
3538 			if (current && parse_tag_value(current, tag, value))
3539 				continue;
3540 		}
3541 
3542 		/* what the heck is it? */
3543 		log_cb(RETRO_LOG_ERROR, LOGPRE "Invalid line in .ART file:\n%s\n", buffer);
3544 	}
3545 
3546 	/* validate the artwork */
3547 	return validate_pieces();
3548 }
3549 
3550 
3551 
3552 #if 0
3553 #pragma mark -
3554 #pragma mark MISC UTILITIES
3555 #endif
3556 
3557 /*-------------------------------------------------
3558 	compute_rgb_components - compute the RGB
3559 	components
3560 -------------------------------------------------*/
3561 
compute_rgb_components(int depth,UINT32 rgb_components[3],UINT32 rgb32_components[3])3562 static int compute_rgb_components(int depth, UINT32 rgb_components[3], UINT32 rgb32_components[3])
3563 {
3564 	UINT32 temp;
3565 	int r, g, b;
3566 
3567 	/* first convert the RGB components we got back into shifts */
3568 	for (temp = rgb32_components[0], rshift = 0; !(temp & 1); temp >>= 1)
3569 		rshift++;
3570 	for (temp = rgb32_components[1], gshift = 0; !(temp & 1); temp >>= 1)
3571 		gshift++;
3572 	for (temp = rgb32_components[2], bshift = 0; !(temp & 1); temp >>= 1)
3573 		bshift++;
3574 
3575 	/* compute the alpha shift for the leftover byte */
3576 	nonalpha_mask = rgb32_components[0] | rgb32_components[1] | rgb32_components[2];
3577 	temp = ~nonalpha_mask;
3578 	for (ashift = 0; !(temp & 1); temp >>= 1)
3579 		ashift++;
3580 
3581 	/* compute a transparent color; this is in the premultiplied space, so alpha is inverted */
3582 	transparent_color = ASSEMBLE_ARGB(0xff,0x00,0x00,0x00);
3583 
3584 	/* allocate a palette lookup */
3585 	palette_lookup = auto_malloc(65536 * sizeof(palette_lookup[0]));
3586 
3587 
3588 	/* switch off the depth */
3589 	switch (depth)
3590 	{
3591 		case 16:
3592 			/* do nothing */
3593 			break;
3594 
3595 		case 32:
3596 			/* copy original components */
3597 			memcpy(rgb_components, rgb32_components, sizeof(rgb_components[0])*3);
3598 			break;
3599 
3600 		case 15:
3601 			/* make up components */
3602 			rgb_components[0] = 0x7c00;
3603 			rgb_components[1] = 0x03e0;
3604 			rgb_components[2] = 0x001f;
3605 
3606 			/* now build up the palette */
3607 			for (r = 0; r < 32; r++)
3608 				for (g = 0; g < 32; g++)
3609 					for (b = 0; b < 32; b++)
3610 					{
3611 						int rr = (r << 3) | (r >> 2);
3612 						int gg = (g << 3) | (g >> 2);
3613 						int bb = (b << 3) | (b >> 2);
3614 						palette_lookup[(r << 10) | (g << 5) | b] = ASSEMBLE_ARGB(0, rr, gg, bb);
3615 					}
3616 			break;
3617 	}
3618 
3619 	return 0;
3620 }
3621 
3622 
3623 
3624 /*-------------------------------------------------
3625 	add_range_to_hint - add a given range to the
3626 	hint record for the specified scanline
3627 -------------------------------------------------*/
3628 
add_range_to_hint(UINT32 * hintbase,int scanline,int startx,int endx)3629 static void add_range_to_hint(UINT32 *hintbase, int scanline, int startx, int endx)
3630 {
3631 	int closestdiff = 100000, closestindex = -1;
3632 	int i;
3633 
3634 	/* first address the correct hint */
3635 	hintbase += scanline * MAX_HINTS_PER_SCANLINE;
3636 
3637 	/* first, look for an intersection */
3638 	for (i = 0; i < MAX_HINTS_PER_SCANLINE; i++)
3639 	{
3640 		UINT32 hint = hintbase[i];
3641 		int hintstart = hint >> 16;
3642 		int hintend = hint & 0xffff;
3643 		int diff;
3644 
3645 		/* stop if we hit a 0 */
3646 		if (hint == 0)
3647 			break;
3648 
3649 		/* do we intersect? */
3650 		if (startx <= hintend && endx >= hintstart)
3651 		{
3652 			closestindex = i;
3653 			goto intersect;
3654 		}
3655 
3656 		/* see how close we are to this entry */
3657 		if (hintend < startx)
3658 			diff = startx - hintend;
3659 		else
3660 			diff = hintstart - endx;
3661 
3662 		/* if this is the closest, remember it */
3663 		if (diff < closestdiff)
3664 		{
3665 			closestdiff = diff;
3666 			closestindex = i;
3667 		}
3668 	}
3669 
3670 	/* okay, we didn't find an intersection; do we have room to add? */
3671 	if (i < MAX_HINTS_PER_SCANLINE)
3672 	{
3673 		UINT32 newhint = (startx << 16) | endx;
3674 
3675 		/* if there's nothing there yet, just assign to the first entry */
3676 		if (i == 0)
3677 			hintbase[0] = newhint;
3678 
3679 		/* otherwise, shuffle the existing entries to make room for us */
3680 		else
3681 		{
3682 			/* determine our new index */
3683 			i = closestindex;
3684 			if (hintbase[i] < newhint)
3685 				i++;
3686 
3687 			/* shift things over */
3688 			if (i < MAX_HINTS_PER_SCANLINE - 1)
3689 				memmove(&hintbase[i+1], &hintbase[i], (MAX_HINTS_PER_SCANLINE - (i+1)) * sizeof(hintbase[0]));
3690 			hintbase[i] = newhint;
3691 		}
3692 		return;
3693 	}
3694 
3695 intersect:
3696 	/* intersect with the closest entry */
3697 	{
3698 		UINT32 hint = hintbase[closestindex];
3699 		int hintstart = hint >> 16;
3700 		int hintend = hint & 0xffff;
3701 
3702 		/* compute the intersection */
3703 		if (startx < hintstart)
3704 			hintstart = startx;
3705 		if (endx > hintend)
3706 			hintend = endx;
3707 		hintbase[closestindex] = (hintstart << 16) | hintend;
3708 	}
3709 }
3710