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(§, 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(§, 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(§, 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