diff --git a/src/emu/crsshair.c b/src/emu/crsshair.c index efa031a7b93..58493fb5e78 100644 --- a/src/emu/crsshair.c +++ b/src/emu/crsshair.c @@ -154,8 +154,9 @@ static void create_bitmap(running_machine *machine, int player) char filename[20]; rgb_t color = crosshair_colors[player]; - /* if we have a bitmap for this player, kill it */ + /* if we have a bitmap and texture for this player, kill it */ global_free(global.bitmap[player]); + machine->render().texture_free(global.texture[player]); if (global.name[player][0] != 0) { @@ -208,9 +209,6 @@ static void create_bitmap(running_machine *machine, int player) void crosshair_init(running_machine *machine) { - const input_port_config *port; - const input_field_config *field; - /* request a callback upon exiting */ machine->add_notifier(MACHINE_NOTIFY_EXIT, crosshair_exit); @@ -221,8 +219,8 @@ void crosshair_init(running_machine *machine) global.auto_time = CROSSHAIR_VISIBILITY_AUTOTIME_DEFAULT; /* determine who needs crosshairs */ - for (port = machine->m_portlist.first(); port != NULL; port = port->next()) - for (field = port->fieldlist; field != NULL; field = field->next) + for (const input_port_config *port = machine->m_portlist.first(); port != NULL; port = port->next()) + for (const input_field_config *field = port->fieldlist; field != NULL; field = field->next) if (field->crossaxis != CROSSHAIR_AXIS_NONE) { int player = field->player; @@ -258,10 +256,8 @@ void crosshair_init(running_machine *machine) static void crosshair_exit(running_machine &machine) { - int player; - /* free bitmaps and textures for each player */ - for (player = 0; player < MAX_PLAYERS; player++) + for (int player = 0; player < MAX_PLAYERS; player++) { machine.render().texture_free(global.texture[player]); global.texture[player] = NULL; diff --git a/src/emu/emucore.h b/src/emu/emucore.h index 417739dc391..71881cf8ac9 100644 --- a/src/emu/emucore.h +++ b/src/emu/emucore.h @@ -374,6 +374,8 @@ public: m_count(0) { } virtual ~simple_list() { reset(); } + + resource_pool &pool() const { return m_pool; } T *first() const { return m_head; } T *last() const { return m_tail; } diff --git a/src/emu/render.c b/src/emu/render.c index f0eee33ae90..48bc9fcdfe4 100644 --- a/src/emu/render.c +++ b/src/emu/render.c @@ -201,21 +201,19 @@ inline void normalize_bounds(render_bounds &bounds) // appropriate layer index and blendmode //------------------------------------------------- -inline int get_layer_and_blendmode(const layout_view &view, int index, int &blendmode) +inline item_layer get_layer_and_blendmode(const layout_view &view, int index, int &blendmode) { - const int *layer_order = layer_order_standard; - int layer; - // if we have multiple backdrop pieces and no overlays, render: // backdrop (add) + screens (add) + bezels (alpha) // else render: // screens (add) + overlays (RGB multiply) + backdrop (add) + bezels (alpha) - if (view.itemlist[ITEM_LAYER_BACKDROP] != NULL && view.itemlist[ITEM_LAYER_BACKDROP]->next != NULL && view.itemlist[ITEM_LAYER_OVERLAY] == NULL) + const int *layer_order = layer_order_standard; + if (view.first_item(ITEM_LAYER_BACKDROP) != NULL && view.first_item(ITEM_LAYER_BACKDROP)->next() != NULL && view.first_item(ITEM_LAYER_OVERLAY) == NULL) layer_order = layer_order_alternate; // select the layer - layer = layer_order[index]; + int layer = layer_order[index]; // pick a blendmode if (layer == ITEM_LAYER_SCREEN && layer_order == layer_order_standard) @@ -227,7 +225,7 @@ inline int get_layer_and_blendmode(const layout_view &view, int index, int &blen else blendmode = BLENDMODE_ALPHA; - return layer; + return item_layer(layer); } @@ -1025,7 +1023,7 @@ render_target::render_target(render_manager &manager, const char *layoutfile, UI : m_next(NULL), m_manager(manager), m_curview(NULL), - m_filelist(NULL), + m_filelist(*auto_alloc(&manager.machine(), simple_list(manager.machine().m_respool))), m_flags(flags), m_listindex(0), m_width(640), @@ -1033,19 +1031,17 @@ render_target::render_target(render_manager &manager, const char *layoutfile, UI m_pixel_aspect(0.0f), m_max_refresh(0), m_orientation(0), - m_layerconfig(LAYER_CONFIG_DEFAULT), m_base_view(NULL), m_base_orientation(ROT0), - m_base_layerconfig(LAYER_CONFIG_DEFAULT), m_maxtexwidth(65536), m_maxtexheight(65536), m_debug_containers(manager.machine().m_respool) { // determine the base layer configuration based on options - if (!options_get_bool(manager.machine().options(), OPTION_USE_BACKDROPS)) m_base_layerconfig &= ~LAYER_CONFIG_ENABLE_BACKDROP; - if (!options_get_bool(manager.machine().options(), OPTION_USE_OVERLAYS)) m_base_layerconfig &= ~LAYER_CONFIG_ENABLE_OVERLAY; - if (!options_get_bool(manager.machine().options(), OPTION_USE_BEZELS)) m_base_layerconfig &= ~LAYER_CONFIG_ENABLE_BEZEL; - if (options_get_bool(manager.machine().options(), OPTION_ARTWORK_CROP)) m_base_layerconfig |= LAYER_CONFIG_ZOOM_TO_SCREEN; + m_base_layerconfig.set_backdrops_enabled(options_get_bool(manager.machine().options(), OPTION_USE_BACKDROPS)); + m_base_layerconfig.set_overlays_enabled(options_get_bool(manager.machine().options(), OPTION_USE_OVERLAYS)); + m_base_layerconfig.set_bezels_enabled(options_get_bool(manager.machine().options(), OPTION_USE_BEZELS)); + m_base_layerconfig.set_zoom_to_screen(options_get_bool(manager.machine().options(), OPTION_ARTWORK_CROP)); // determine the base orientation based on options m_orientation = ROT0; @@ -1086,13 +1082,7 @@ render_target::render_target(render_manager &manager, const char *layoutfile, UI render_target::~render_target() { - // free the layout files - while (m_filelist != NULL) - { - layout_file *temp = m_filelist; - m_filelist = temp->next; - layout_file_free(temp); - } + auto_free(&m_manager.machine(), &m_filelist); } @@ -1133,18 +1123,6 @@ void render_target::set_bounds(INT32 width, INT32 height, float pixel_aspect) } -//------------------------------------------------- -// set_layer_config - set the layer config of a -// target -//------------------------------------------------- - -void render_target::set_layer_config(int layerconfig) -{ - m_layerconfig = layerconfig; - layout_view_recompute(m_curview, layerconfig); -} - - //------------------------------------------------- // set_view - dynamically change the view for // a target @@ -1156,7 +1134,7 @@ void render_target::set_view(int viewindex) if (view != NULL) { m_curview = view; - layout_view_recompute(view, m_layerconfig); + view->recompute(m_layerconfig); } } @@ -1180,7 +1158,7 @@ void render_target::set_max_texture_size(int maxwidth, int maxheight) const char *render_target::view_name(int viewindex) { layout_view *view = view_by_index(viewindex); - return (view != NULL) ? view->name : NULL; + return (view != NULL) ? view->name() : NULL; } @@ -1190,10 +1168,10 @@ const char *render_target::view_name(int viewindex) // given view //------------------------------------------------- -UINT32 render_target::view_screens(int viewindex) +const render_screen_list &render_target::view_screens(int viewindex) { layout_view *view = view_by_index(viewindex); - return (view != NULL) ? view->screens : NULL; + return (view != NULL) ? view->screens() : s_empty_screen_list; } @@ -1212,7 +1190,7 @@ void render_target::compute_visible_area(INT32 target_width, INT32 target_height if (target_pixel_aspect != 0.0f) { // start with the aspect ratio of the square pixel layout - width = (zoom_to_screen() && m_curview->screens > 0) ? m_curview->scraspect : m_curview->aspect; + width = m_curview->effective_aspect(m_layerconfig); height = 1.0f; // first apply target orientation @@ -1254,44 +1232,43 @@ void render_target::compute_minimum_size(INT32 &minwidth, INT32 &minheight) { float maxxscale = 1.0f, maxyscale = 1.0f; int screens_considered = 0; + + // early exit in case we are called between device teardown and render teardown + if (m_manager.machine().m_devicelist.count() == 0) + { + minwidth = 640; + minheight = 480; + return; + } // scan the current view for all screens - for (int layer = 0; layer < ITEM_LAYER_MAX; layer++) + for (item_layer layer = ITEM_LAYER_FIRST; layer < ITEM_LAYER_MAX; layer++) // iterate over items in the layer - for (view_item *item = m_curview->itemlist[layer]; item != NULL; item = item->next) - if (item->element == NULL) + for (layout_view::item *curitem = m_curview->first_item(layer); curitem != NULL; curitem = curitem->next()) + if (curitem->screen() != NULL) { - const screen_device_config *scrconfig = downcast(m_manager.machine().config->m_devicelist.find(SCREEN, item->index)); - screen_device *screendev = m_manager.machine().device(scrconfig->tag()); - - // we may be called very early, before machine->visible_area is initialized; handle that case + // use a hard-coded default visible area for vector screens + screen_device *screen = curitem->screen(); const rectangle vectorvis = { 0, 639, 0, 479 }; - const rectangle *visarea = NULL; - if (scrconfig->screen_type() == SCREEN_TYPE_VECTOR) - visarea = &vectorvis; - else if (screendev != NULL && screendev->started()) - visarea = &screendev->visible_area(); - else - visarea = &scrconfig->visible_area(); + const rectangle &visarea = (screen->screen_type() == SCREEN_TYPE_VECTOR) ? vectorvis : screen->visible_area(); // apply target orientation to the bounds - render_bounds bounds = item->bounds; + render_bounds bounds = curitem->bounds(); apply_orientation(bounds, m_orientation); normalize_bounds(bounds); // based on the orientation of the screen container, check the bitmap - render_container *container = m_manager.m_screen_container_list.find(item->index); float xscale, yscale; - if (!(orientation_add(m_orientation, container->orientation()) & ORIENTATION_SWAP_XY)) + if (!(orientation_add(m_orientation, screen->container().orientation()) & ORIENTATION_SWAP_XY)) { - xscale = (float)(visarea->max_x + 1 - visarea->min_x) / (bounds.x1 - bounds.x0); - yscale = (float)(visarea->max_y + 1 - visarea->min_y) / (bounds.y1 - bounds.y0); + xscale = (float)(visarea.max_x + 1 - visarea.min_x) / (bounds.x1 - bounds.x0); + yscale = (float)(visarea.max_y + 1 - visarea.min_y) / (bounds.y1 - bounds.y0); } else { - xscale = (float)(visarea->max_y + 1 - visarea->min_y) / (bounds.x1 - bounds.x0); - yscale = (float)(visarea->max_x + 1 - visarea->min_x) / (bounds.y1 - bounds.y0); + xscale = (float)(visarea.max_y + 1 - visarea.min_y) / (bounds.x1 - bounds.x0); + yscale = (float)(visarea.max_x + 1 - visarea.min_x) / (bounds.y1 - bounds.y0); } // pick the greater @@ -1348,17 +1325,17 @@ render_primitive_list &render_target::get_primitives() // iterate over layers back-to-front, but only if we're running if (m_manager.machine().phase() >= MACHINE_PHASE_RESET) - for (int layernum = 0; layernum < ITEM_LAYER_MAX; layernum++) + for (item_layer layernum = ITEM_LAYER_FIRST; layernum < ITEM_LAYER_MAX; layernum++) { int blendmode; - int layer = get_layer_and_blendmode(*m_curview, layernum, blendmode); - if (m_curview->layenabled[layer]) + item_layer layer = get_layer_and_blendmode(*m_curview, layernum, blendmode); + if (m_curview->layer_enabled(layer)) { // iterate over items in the layer - for (view_item *item = m_curview->itemlist[layer]; item != NULL; item = item->next) + for (layout_view::item *curitem = m_curview->first_item(layer); curitem != NULL; curitem = curitem->next()) { // first apply orientation to the bounds - render_bounds bounds = item->bounds; + render_bounds bounds = curitem->bounds(); apply_orientation(bounds, root_xform.orientation); normalize_bounds(bounds); @@ -1368,32 +1345,18 @@ render_primitive_list &render_target::get_primitives() item_xform.yoffs = root_xform.yoffs + bounds.y0 * root_xform.yscale; item_xform.xscale = (bounds.x1 - bounds.x0) * root_xform.xscale; item_xform.yscale = (bounds.y1 - bounds.y0) * root_xform.yscale; - item_xform.color.r = item->color.r * root_xform.color.r; - item_xform.color.g = item->color.g * root_xform.color.g; - item_xform.color.b = item->color.b * root_xform.color.b; - item_xform.color.a = item->color.a * root_xform.color.a; - item_xform.orientation = orientation_add(item->orientation, root_xform.orientation); + item_xform.color.r = curitem->color().r * root_xform.color.r; + item_xform.color.g = curitem->color().g * root_xform.color.g; + item_xform.color.b = curitem->color().b * root_xform.color.b; + item_xform.color.a = curitem->color().a * root_xform.color.a; + item_xform.orientation = orientation_add(curitem->orientation(), root_xform.orientation); item_xform.no_center = false; // if there is no associated element, it must be a screen element - if (item->element != NULL) - { - int state = 0; - if (item->output_name[0] != 0) - state = output_get_value(item->output_name); - else if (item->input_tag[0] != 0) - { - const input_field_config *field = input_field_by_tag_and_mask(m_manager.machine().m_portlist, item->input_tag, item->input_mask); - if (field != NULL) - state = ((input_port_read_safe(&m_manager.machine(), item->input_tag, 0) ^ field->defvalue) & item->input_mask) ? 1 : 0; - } - add_element_primitives(list, item_xform, *item->element, state, blendmode); - } + if (curitem->screen() != NULL) + add_container_primitives(list, item_xform, curitem->screen()->container(), blendmode); else - { - render_container *container = m_manager.m_screen_container_list.find(item->index); - add_container_primitives(list, item_xform, *container, blendmode); - } + add_element_primitives(list, item_xform, *curitem->element(), curitem->state(), blendmode); } } } @@ -1468,8 +1431,9 @@ render_primitive_list &render_target::get_primitives() bool render_target::map_point_container(INT32 target_x, INT32 target_y, render_container &container, float &container_x, float &container_y) { - view_item *item; - return map_point_internal(target_x, target_y, &container, container_x, container_y, item); + const char *input_tag; + UINT32 input_mask; + return map_point_internal(target_x, target_y, &container, container_x, container_y, input_tag, input_mask); } @@ -1481,15 +1445,7 @@ bool render_target::map_point_container(INT32 target_x, INT32 target_y, render_c bool render_target::map_point_input(INT32 target_x, INT32 target_y, const char *&input_tag, UINT32 &input_mask, float &input_x, float &input_y) { - view_item *item = NULL; - - bool result = map_point_internal(target_x, target_y, NULL, input_x, input_y, item); - if (result && item != NULL) - { - input_tag = item->input_tag; - input_mask = item->input_mask; - } - return result; + return map_point_internal(target_x, target_y, NULL, input_x, input_y, input_tag, input_mask); } @@ -1547,6 +1503,17 @@ void render_target::debug_top(render_container &container) } +//------------------------------------------------- +// update_layer_config - recompute after a layer +// config change +//------------------------------------------------- + +void render_target::update_layer_config() +{ + m_curview->recompute(m_layerconfig); +} + + //------------------------------------------------- // load_layout_files - load layout files for a // given render target @@ -1554,16 +1521,10 @@ void render_target::debug_top(render_container &container) void render_target::load_layout_files(const char *layoutfile, bool singlefile) { - layout_file **nextfile = &m_filelist; - // if there's an explicit file, load that first const char *basename = m_manager.machine().basename(); if (layoutfile != NULL) - { - *nextfile = layout_file_load(m_manager.machine(), basename, layoutfile); - if (*nextfile != NULL) - nextfile = &(*nextfile)->next; - } + load_layout_file(basename, layoutfile); // if we're only loading this file, we know our final result if (singlefile) @@ -1571,50 +1532,95 @@ void render_target::load_layout_files(const char *layoutfile, bool singlefile) // try to load a file based on the driver name const game_driver *gamedrv = m_manager.machine().gamedrv; - *nextfile = layout_file_load(m_manager.machine(), basename, gamedrv->name); - if (*nextfile == NULL) - *nextfile = layout_file_load(m_manager.machine(), basename, "default"); - if (*nextfile != NULL) - nextfile = &(*nextfile)->next; + if (!load_layout_file(basename, gamedrv->name)) + load_layout_file(basename, "default"); // if a default view has been specified, use that as a fallback if (gamedrv->default_layout != NULL) - { - *nextfile = layout_file_load(m_manager.machine(), NULL, gamedrv->default_layout); - if (*nextfile != NULL) - nextfile = &(*nextfile)->next; - } + load_layout_file(NULL, gamedrv->default_layout); if (m_manager.machine().m_config.m_default_layout != NULL) - { - *nextfile = layout_file_load(m_manager.machine(), NULL, m_manager.machine().m_config.m_default_layout); - if (*nextfile != NULL) - nextfile = &(*nextfile)->next; - } + load_layout_file(NULL, m_manager.machine().m_config.m_default_layout); // try to load another file based on the parent driver name const game_driver *cloneof = driver_get_clone(gamedrv); if (cloneof != NULL) - { - *nextfile = layout_file_load(m_manager.machine(), cloneof->name, cloneof->name); - if (*nextfile == NULL) - *nextfile = layout_file_load(m_manager.machine(), cloneof->name, "default"); - if (*nextfile != NULL) - nextfile = &(*nextfile)->next; - } + if (!load_layout_file(cloneof->name, cloneof->name)) + load_layout_file(cloneof->name, "default"); // now do the built-in layouts for single-screen games if (screen_count(m_manager.machine().m_config) == 1) { if (gamedrv->flags & ORIENTATION_SWAP_XY) - *nextfile = layout_file_load(m_manager.machine(), NULL, layout_vertical); + load_layout_file(NULL, layout_vertical); else - *nextfile = layout_file_load(m_manager.machine(), NULL, layout_horizont); - assert_always(*nextfile != NULL, "Couldn't parse default layout??"); - nextfile = &(*nextfile)->next; + load_layout_file(NULL, layout_horizont); + assert_always(m_filelist.count() > 0, "Couldn't parse default layout??"); } } +//------------------------------------------------- +// load_layout_file - load a single layout file +// and append it to our list +//------------------------------------------------- + +bool render_target::load_layout_file(const char *dirname, const char *filename) +{ + // if the first character of the "file" is an open brace, assume it is an XML string + xml_data_node *rootnode; + if (filename[0] == '<') + rootnode = xml_string_read(filename, NULL); + + // otherwise, assume it is a file + else + { + // build the path and optionally prepend the directory + astring fname(filename, ".lay"); + if (dirname != NULL) + fname.ins(0, PATH_SEPARATOR).ins(0, dirname); + + // attempt to open the file; bail if we can't + mame_file *layoutfile; + file_error filerr = mame_fopen(SEARCHPATH_ARTWORK, fname, OPEN_FLAG_READ, &layoutfile); + if (filerr != FILERR_NONE) + return false; + + // read the file + rootnode = xml_file_read(mame_core_file(layoutfile), NULL); + mame_fclose(layoutfile); + } + + // if we didn't get a properly-formatted XML file, record a warning and exit + if (rootnode == NULL) + { + if (filename[0] != '<') + mame_printf_warning("Improperly formatted XML file '%s', ignorning\n", filename); + else + mame_printf_warning("Improperly formatted XML string, ignorning"); + return false; + } + + // parse and catch any errors + bool result = true; + try + { + m_filelist.append(*auto_alloc(&m_manager.machine(), layout_file(m_manager.machine(), *rootnode, dirname))); + } + catch (emu_fatalerror &err) + { + if (filename[0] != '<') + mame_printf_warning("Error in XML file '%s': %s\n", filename, err.string()); + else + mame_printf_warning("Error in XML string: %s", err.string()); + result = false; + } + + // free the root node + xml_file_free(rootnode); + return result; +} + + //------------------------------------------------- // add_container_primitives - add primitives // based on the container @@ -1767,7 +1773,7 @@ void render_target::add_container_primitives(render_primitive_list &list, const } // add the overlay if it exists - if (container.overlay() != NULL && screen_overlay_enabled()) + if (container.overlay() != NULL && m_layerconfig.screen_overlay_enabled()) { INT32 width, height; @@ -1801,16 +1807,16 @@ void render_target::add_container_primitives(render_primitive_list &list, const // for an element in the current state //------------------------------------------------- -void render_target::add_element_primitives(render_primitive_list &list, const object_transform &xform, const layout_element &element, int state, int blendmode) +void render_target::add_element_primitives(render_primitive_list &list, const object_transform &xform, layout_element &element, int state, int blendmode) { // if we're out of range, bail - if (state > element.maxstate) + if (state > element.maxstate()) return; if (state < 0) state = 0; // get a pointer to the relevant texture - render_texture *texture = element.elemtex[state].texture; + render_texture *texture = element.state_texture(state); if (texture != NULL) { render_primitive *prim = list.alloc(render_primitive::QUAD); @@ -1856,11 +1862,13 @@ void render_target::add_element_primitives(render_primitive_list &list, const ob // mapping points //------------------------------------------------- -bool render_target::map_point_internal(INT32 target_x, INT32 target_y, render_container *container, float &mapped_x, float &mapped_y, view_item *&mapped_item) +bool render_target::map_point_internal(INT32 target_x, INT32 target_y, render_container *container, float &mapped_x, float &mapped_y, const char *&mapped_input_tag, UINT32 &mapped_input_mask) { // default to point not mapped mapped_x = -1.0; mapped_y = -1.0; + mapped_input_tag = NULL; + mapped_input_mask = 0; // convert target coordinates to float float target_fx = (float)target_x / m_width; @@ -1875,39 +1883,38 @@ bool render_target::map_point_internal(INT32 target_x, INT32 target_y, render_co // this point was successfully mapped mapped_x = target_fx; mapped_y = target_fy; - mapped_item = NULL; return true; } return false; } // loop through each layer - for (int layernum = 0; layernum < ITEM_LAYER_MAX; layernum++) + for (item_layer layernum = ITEM_LAYER_FIRST; layernum < ITEM_LAYER_MAX; layernum++) { int blendmode; - int layer = get_layer_and_blendmode(*m_curview, layernum, blendmode); - if (m_curview->layenabled[layer]) + item_layer layer = get_layer_and_blendmode(*m_curview, layernum, blendmode); + if (m_curview->layer_enabled(layer)) { // iterate over items in the layer - for (view_item *item = m_curview->itemlist[layer]; item != NULL; item = item->next) + for (layout_view::item *item = m_curview->first_item(layer); item != NULL; item = item->next()) { bool checkit; // if we're looking for a particular container, verify that we have the right one if (container != NULL) - checkit = (item->element == NULL && container == m_manager.m_screen_container_list.find(item->index)); + checkit = (item->screen() != NULL && &item->screen()->container() == container); // otherwise, assume we're looking for an input else - checkit = (item->input_tag[0] != 0); + checkit = item->has_input(); // this target is worth looking at; now check the point - if (checkit && target_fx >= item->bounds.x0 && target_fx < item->bounds.x1 && target_fy >= item->bounds.y0 && target_fy < item->bounds.y1) + if (checkit && target_fx >= item->bounds().x0 && target_fx < item->bounds().x1 && target_fy >= item->bounds().y0 && target_fy < item->bounds().y1) { // point successfully mapped - mapped_x = (target_fx - item->bounds.x0) / (item->bounds.x1 - item->bounds.x0); - mapped_y = (target_fy - item->bounds.y0) / (item->bounds.y1 - item->bounds.y0); - mapped_item = item; + mapped_x = (target_fx - item->bounds().x0) / (item->bounds().x1 - item->bounds().x0); + mapped_y = (target_fy - item->bounds().y0) / (item->bounds().y1 - item->bounds().y0); + mapped_input_tag = item->input_tag_and_mask(mapped_input_mask); return true; } } @@ -1925,9 +1932,9 @@ bool render_target::map_point_internal(INT32 target_x, INT32 target_y, render_co layout_view *render_target::view_by_index(int index) const { // scan the list of views within each layout, skipping those that don't apply - for (layout_file *file = m_filelist; file != NULL; file = file->next) - for (layout_view *view = file->viewlist; view != NULL; view = view->next) - if (!(m_flags & RENDER_CREATE_NO_ART) || !layout_view_has_art(view)) + for (layout_file *file = m_filelist.first(); file != NULL; file = file->next()) + for (layout_view *view = file->first_view(); view != NULL; view = view->next()) + if (!(m_flags & RENDER_CREATE_NO_ART) || !view->has_art()) if (index-- == 0) return view; return NULL; @@ -1945,9 +1952,9 @@ int render_target::view_index(layout_view &targetview) const int index = 0; // scan the list of views within each layout, skipping those that don't apply - for (layout_file *file = m_filelist; file != NULL; file = file->next) - for (layout_view *view = file->viewlist; view != NULL; view = view->next) - if (!(m_flags & RENDER_CREATE_NO_ART) || !layout_view_has_art(view)) + for (layout_file *file = m_filelist.first(); file != NULL; file = file->next()) + for (layout_view *view = file->first_view(); view != NULL; view = view->next()) + if (!(m_flags & RENDER_CREATE_NO_ART) || !view->has_art()) { if (&targetview == view) return index; @@ -2038,17 +2045,17 @@ bool render_target::config_save(xml_data_node &targetnode) // output the view if (m_curview != m_base_view) { - xml_set_attribute(&targetnode, "view", m_curview->name); + xml_set_attribute(&targetnode, "view", m_curview->name()); changed = true; } // output the layer config if (m_layerconfig != m_base_layerconfig) { - xml_set_attribute_int(&targetnode, "backdrops", backdrops_enabled()); - xml_set_attribute_int(&targetnode, "overlays", overlays_enabled()); - xml_set_attribute_int(&targetnode, "bezels", bezels_enabled()); - xml_set_attribute_int(&targetnode, "zoom", zoom_to_screen()); + xml_set_attribute_int(&targetnode, "backdrops", m_layerconfig.backdrops_enabled()); + xml_set_attribute_int(&targetnode, "overlays", m_layerconfig.overlays_enabled()); + xml_set_attribute_int(&targetnode, "bezels", m_layerconfig.bezels_enabled()); + xml_set_attribute_int(&targetnode, "zoom", m_layerconfig.zoom_to_screen()); changed = true; } @@ -2360,7 +2367,7 @@ render_manager::render_manager(running_machine &machine) // create one container per screen for (screen_device *screen = screen_first(machine); screen != NULL; screen = screen_next(screen)) - container_alloc(screen); + screen->set_container(*container_alloc(screen)); } @@ -2385,15 +2392,11 @@ render_manager::~render_manager() bool render_manager::is_live(screen_device &screen) const { - int screen_index = screen.machine->m_devicelist.index(SCREEN, screen.tag()); - assert(screen_index != -1); - // iterate over all live targets and or together their screen masks - UINT32 bitmask = 0; for (render_target *target = m_targetlist.first(); target != NULL; target = target->next()) - bitmask |= target->view_screens(target->view()); - - return (bitmask & (1 << screen_index)) ? true : false; + if (target->view_screens(target->view()).contains(screen)) + return true; + return false; } @@ -2484,21 +2487,6 @@ float render_manager::ui_aspect() } -//------------------------------------------------- -// container_for_screen - return the container -// allocated for the given screen device -//------------------------------------------------- - -render_container *render_manager::container_for_screen(screen_device *screen) -{ - // scan the list of screen containers for a match - for (render_container *container = m_screen_container_list.first(); container != NULL; container = container->next()) - if (container->screen() == screen) - return container; - return NULL; -} - - //------------------------------------------------- // texture_alloc - allocate a new texture //------------------------------------------------- diff --git a/src/emu/render.h b/src/emu/render.h index 599927de73b..b615da4309d 100644 --- a/src/emu/render.h +++ b/src/emu/render.h @@ -113,19 +113,6 @@ const UINT8 RENDER_CREATE_SINGLE_FILE = 0x02; // only load views from the file const UINT8 RENDER_CREATE_HIDDEN = 0x04; // don't make this target visible -// layer config masks -const UINT8 LAYER_CONFIG_ENABLE_BACKDROP = 0x01; // enable backdrop layers -const UINT8 LAYER_CONFIG_ENABLE_OVERLAY = 0x02; // enable overlay layers -const UINT8 LAYER_CONFIG_ENABLE_BEZEL = 0x04; // enable bezel layers -const UINT8 LAYER_CONFIG_ZOOM_TO_SCREEN = 0x08; // zoom to screen area by default -const UINT8 LAYER_CONFIG_ENABLE_SCREEN_OVERLAY = 0x10; // enable screen overlays - -const UINT8 LAYER_CONFIG_DEFAULT = (LAYER_CONFIG_ENABLE_BACKDROP | - LAYER_CONFIG_ENABLE_OVERLAY | - LAYER_CONFIG_ENABLE_BEZEL | - LAYER_CONFIG_ENABLE_SCREEN_OVERLAY); - - // flags for primitives const int PRIMFLAG_TEXORIENT_SHIFT = 0; const UINT32 PRIMFLAG_TEXORIENT_MASK = 15 << PRIMFLAG_TEXORIENT_SHIFT; @@ -183,10 +170,9 @@ class render_manager; typedef struct _xml_data_node xml_data_node; typedef struct _render_font render_font; struct object_transform; -typedef struct _layout_element layout_element; -typedef struct _layout_view layout_view; -typedef struct _view_item view_item; -typedef struct _layout_file layout_file; +class layout_element; +class layout_view; +class layout_file; // texture scaling callback @@ -243,6 +229,90 @@ struct render_texinfo }; +// ======================> render_screen_list + +// a render_screen_list is a list of screen_devices +class render_screen_list +{ + // screen list item + class item + { + friend class simple_list; + friend class render_screen_list; + + public: + // construction/destruction + item(screen_device &screen) + : m_next(NULL), + m_screen(screen) { } + + // state + item * m_next; // next screen in list + screen_device & m_screen; // reference to screen device + }; + +public: + // construction/destruction + render_screen_list(resource_pool &pool = global_resource_pool) + : m_list(pool) { } + + // getters + int count() const { return m_list.count(); } + + // operations + void add(screen_device &screen) { m_list.append(*pool_alloc(m_list.pool(), item(screen))); } + void reset() { m_list.reset(); } + + // query + bool contains(screen_device &screen) const + { + for (item *curitem = m_list.first(); curitem != NULL; curitem = curitem->m_next) + if (&curitem->m_screen == &screen) return true; + return false; + } + +private: + // internal state + simple_list m_list; +}; + + +// ======================> render_layer_config + +// render_layer_config - describes the state of layers +class render_layer_config +{ + static const UINT8 ENABLE_BACKDROP = 0x01; // enable backdrop layers + static const UINT8 ENABLE_OVERLAY = 0x02; // enable overlay layers + static const UINT8 ENABLE_BEZEL = 0x04; // enable bezel layers + static const UINT8 ZOOM_TO_SCREEN = 0x08; // zoom to screen area by default + static const UINT8 ENABLE_SCREEN_OVERLAY = 0x10; // enable screen overlays + static const UINT8 DEFAULT = ENABLE_BACKDROP | ENABLE_OVERLAY | ENABLE_BEZEL | ENABLE_SCREEN_OVERLAY; + +public: + render_layer_config() + : m_state(DEFAULT) { } + + bool operator==(const render_layer_config &rhs) const { return m_state == rhs.m_state; } + bool operator!=(const render_layer_config &rhs) const { return m_state != rhs.m_state; } + + bool backdrops_enabled() const { return ((m_state & ENABLE_BACKDROP) != 0); } + bool overlays_enabled() const { return ((m_state & ENABLE_OVERLAY) != 0); } + bool bezels_enabled() const { return ((m_state & ENABLE_BEZEL) != 0); } + bool screen_overlay_enabled() const { return ((m_state & ENABLE_SCREEN_OVERLAY) != 0); } + bool zoom_to_screen() const { return ((m_state & ZOOM_TO_SCREEN) != 0); } + + render_layer_config &set_backdrops_enabled(bool enable) { if (enable) m_state |= ENABLE_BACKDROP; else m_state &= ~ENABLE_BACKDROP; return *this; } + render_layer_config &set_overlays_enabled(bool enable) { if (enable) m_state |= ENABLE_OVERLAY; else m_state &= ~ENABLE_OVERLAY; return *this; } + render_layer_config &set_bezels_enabled(bool enable) { if (enable) m_state |= ENABLE_BEZEL; else m_state &= ~ENABLE_BEZEL; return *this; } + render_layer_config &set_screen_overlay_enabled(bool enable) { if (enable) m_state |= ENABLE_SCREEN_OVERLAY; else m_state &= ~ENABLE_SCREEN_OVERLAY; return *this; } + render_layer_config &set_zoom_to_screen(bool zoom) { if (zoom) m_state |= ZOOM_TO_SCREEN; else m_state &= ~ZOOM_TO_SCREEN; return *this; } + +private: + UINT8 m_state; +}; + + // ======================> render_primitive // render_primitive - a single low-level primitive for the rendering engine @@ -530,14 +600,9 @@ public: float pixel_aspect() const { return m_pixel_aspect; } float max_update_rate() const { return m_max_refresh; } int orientation() const { return m_orientation; } - int layer_config() const { return m_layerconfig; } + render_layer_config layer_config() const { return m_layerconfig; } int view() const { return view_index(*m_curview); } bool hidden() const { return ((m_flags & RENDER_CREATE_HIDDEN) != 0); } - bool backdrops_enabled() const { return (m_layerconfig & LAYER_CONFIG_ENABLE_BACKDROP) != 0; } - bool overlays_enabled() const { return (m_layerconfig & LAYER_CONFIG_ENABLE_OVERLAY) != 0; } - bool bezels_enabled() const { return (m_layerconfig & LAYER_CONFIG_ENABLE_BEZEL) != 0; } - bool screen_overlay_enabled() const { return (m_layerconfig & LAYER_CONFIG_ENABLE_SCREEN_OVERLAY) != 0; } - bool zoom_to_screen() const { return (m_layerconfig & LAYER_CONFIG_ZOOM_TO_SCREEN) != 0; } bool is_ui_target() const; int index() const; @@ -545,18 +610,26 @@ public: void set_bounds(INT32 width, INT32 height, float pixel_aspect = 0); void set_max_update_rate(float updates_per_second) { m_max_refresh = updates_per_second; } void set_orientation(int orientation) { m_orientation = orientation; } - void set_layer_config(int layerconfig); void set_view(int viewindex); void set_max_texture_size(int maxwidth, int maxheight); - void set_backdrops_enabled(bool enable) { set_layer_config(enable ? (m_layerconfig | LAYER_CONFIG_ENABLE_BACKDROP) : (m_layerconfig & ~LAYER_CONFIG_ENABLE_BACKDROP)); } - void set_overlays_enabled(bool enable) { set_layer_config(enable ? (m_layerconfig | LAYER_CONFIG_ENABLE_OVERLAY) : (m_layerconfig & ~LAYER_CONFIG_ENABLE_OVERLAY)); } - void set_bezels_enabled(bool enable) { set_layer_config(enable ? (m_layerconfig | LAYER_CONFIG_ENABLE_BEZEL) : (m_layerconfig & ~LAYER_CONFIG_ENABLE_BEZEL)); } - void set_screen_overlay_enabled(bool enable) { set_layer_config(enable ? (m_layerconfig | LAYER_CONFIG_ENABLE_SCREEN_OVERLAY) : (m_layerconfig & ~LAYER_CONFIG_ENABLE_SCREEN_OVERLAY)); } - void set_zoom_to_screen(bool zoom) { set_layer_config(zoom ? (m_layerconfig | LAYER_CONFIG_ZOOM_TO_SCREEN) : (m_layerconfig & ~LAYER_CONFIG_ZOOM_TO_SCREEN)); } + + // layer config getters + bool backdrops_enabled() const { return m_layerconfig.backdrops_enabled(); } + bool overlays_enabled() const { return m_layerconfig.overlays_enabled(); } + bool bezels_enabled() const { return m_layerconfig.bezels_enabled(); } + bool screen_overlay_enabled() const { return m_layerconfig.screen_overlay_enabled(); } + bool zoom_to_screen() const { return m_layerconfig.zoom_to_screen(); } + + // layer config setters + void set_backdrops_enabled(bool enable) { m_layerconfig.set_backdrops_enabled(enable); update_layer_config(); } + void set_overlays_enabled(bool enable) { m_layerconfig.set_overlays_enabled(enable); update_layer_config(); } + void set_bezels_enabled(bool enable) { m_layerconfig.set_bezels_enabled(enable); update_layer_config(); } + void set_screen_overlay_enabled(bool enable) { m_layerconfig.set_screen_overlay_enabled(enable); update_layer_config(); } + void set_zoom_to_screen(bool zoom) { m_layerconfig.set_zoom_to_screen(zoom); update_layer_config(); } // view information const char *view_name(int viewindex); - UINT32 view_screens(int viewindex); + const render_screen_list &view_screens(int viewindex); // bounds computations void compute_visible_area(INT32 target_width, INT32 target_height, float target_pixel_aspect, int target_orientation, INT32 &visible_width, INT32 &visible_height); @@ -579,10 +652,12 @@ public: private: // internal helpers + void update_layer_config(); void load_layout_files(const char *layoutfile, bool singlefile); + bool load_layout_file(const char *dirname, const char *filename); void add_container_primitives(render_primitive_list &list, const object_transform &xform, render_container &container, int blendmode); - void add_element_primitives(render_primitive_list &list, const object_transform &xform, const layout_element &element, int state, int blendmode); - bool map_point_internal(INT32 target_x, INT32 target_y, render_container *container, float &mapped_x, float &mapped_y, view_item *&mapped_item); + void add_element_primitives(render_primitive_list &list, const object_transform &xform, layout_element &element, int state, int blendmode); + bool map_point_internal(INT32 target_x, INT32 target_y, render_container *container, float &mapped_x, float &mapped_y, const char *&mapped_input_tag, UINT32 &mapped_input_mask); // config callbacks void config_load(xml_data_node &targetnode); @@ -606,7 +681,7 @@ private: render_target * m_next; // link to next target render_manager & m_manager; // reference to our owning manager layout_view * m_curview; // current view - layout_file * m_filelist; // list of layout files + simple_list &m_filelist; // list of layout files UINT32 m_flags; // creation flags render_primitive_list m_primlist[NUM_PRIMLISTS]; // list of primitives int m_listindex; // index of next primlist to use @@ -616,15 +691,17 @@ private: float m_pixel_aspect; // aspect ratio of individual pixels float m_max_refresh; // maximum refresh rate, 0 or if none int m_orientation; // orientation - int m_layerconfig; // layer configuration + render_layer_config m_layerconfig; // layer configuration layout_view * m_base_view; // the view at the time of first frame int m_base_orientation; // the orientation at the time of first frame - int m_base_layerconfig; // the layer configuration at the time of first frame + render_layer_config m_base_layerconfig; // the layer configuration at the time of first frame int m_maxtexwidth; // maximum width of a texture int m_maxtexheight; // maximum height of a texture simple_list m_debug_containers; // list of debug containers INT32 m_clear_extent_count; // number of clear extents INT32 m_clear_extents[MAX_CLEAR_EXTENTS]; // array of clear extents + + static const render_screen_list s_empty_screen_list; }; @@ -658,9 +735,6 @@ public: void set_ui_target(render_target &target) { m_ui_target = ⌖ } float ui_aspect(); - // screen containers - render_container *container_for_screen(screen_device *screen); - // UI containers render_container &ui_container() const { assert(m_ui_container != NULL); return *m_ui_container; } diff --git a/src/emu/rendlay.c b/src/emu/rendlay.c index 023e144732c..1886f44ab20 100644 --- a/src/emu/rendlay.c +++ b/src/emu/rendlay.c @@ -4,19 +4,38 @@ Core rendering layout parser and manager. - Copyright Nicola Salmoria and the MAME Team. - Visit http://mamedev.org for licensing and usage restrictions. - **************************************************************************** - Notes: + Copyright Aaron Giles + All rights reserved. - Unlike the old system, the artwork is not rotated with the game - orientation. This is to support odd configurations like two - monitors in different orientations. You can specify an orientation - for a backdrop/screen/overlay/bezel element, but it only applies - to the artwork itself, and does not affect coordinates in any way. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name 'MAME' nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + +**************************************************************************** Overview of objects: @@ -72,19 +91,19 @@ STANDARD LAYOUTS ***************************************************************************/ -/* single screen layouts */ +// single screen layouts #include "horizont.lh" #include "vertical.lh" -/* dual screen layouts */ +// dual screen layouts #include "dualhsxs.lh" #include "dualhovu.lh" #include "dualhuov.lh" -/* triple screen layouts */ +// triple screen layouts #include "triphsxs.lh" -/* generic color overlay layouts */ +// generic color overlay layouts #include "ho20ffff.lh" #include "ho2eff2e.lh" #include "ho4f893d.lh" @@ -96,94 +115,39 @@ -/*************************************************************************** - CONSTANTS -***************************************************************************/ +//************************************************************************** +// CONSTANTS +//************************************************************************** -#define LAYOUT_VERSION 2 - -#define LINE_CAP_NONE 0 -#define LINE_CAP_START 1 -#define LINE_CAP_END 2 +const int LAYOUT_VERSION = 2; enum { - COMPONENT_TYPE_IMAGE = 0, - COMPONENT_TYPE_RECT, - COMPONENT_TYPE_DISK, - COMPONENT_TYPE_TEXT, - COMPONENT_TYPE_LED7SEG, - COMPONENT_TYPE_LED14SEG, - COMPONENT_TYPE_LED16SEG, - COMPONENT_TYPE_LED14SEGSC, - COMPONENT_TYPE_LED16SEGSC, - COMPONENT_TYPE_DOTMATRIX, - COMPONENT_TYPE_MAX -}; - - -/*************************************************************************** - TYPE DEFINITIONS -***************************************************************************/ - -/* an element_component represents an image, rectangle, or disk in an element */ -struct _element_component -{ - element_component * next; /* link to next component */ - int type; /* type of component */ - int state; /* state where this component is visible (-1 means all states) */ - render_bounds bounds; /* bounds of the element */ - render_color color; /* color of the element */ - const char * string; /* string for text components */ - bitmap_t * bitmap; /* source bitmap for images */ - const char * dirname; /* directory name of image file (for lazy loading) */ - const char * imagefile; /* name of the image file (for lazy loading) */ - const char * alphafile; /* name of the alpha file (for lazy loading) */ - int hasalpha; /* is there any alpha component present? */ + LINE_CAP_NONE = 0, + LINE_CAP_START = 1, + LINE_CAP_END = 2 }; -/*************************************************************************** - FUNCTION PROTOTYPES -***************************************************************************/ +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** -/* layout elements */ -static void layout_element_scale(bitmap_t &dest, const bitmap_t &source, const rectangle &sbounds, void *param); -static void layout_element_draw_rect(bitmap_t &dest, const rectangle &bounds, const render_color &color); -static void layout_element_draw_disk(bitmap_t &dest, const rectangle &bounds, const render_color &color); -static void layout_element_draw_text(running_machine &machine, bitmap_t &dest, const rectangle &bounds, const render_color &color, const char *string); -static void layout_element_draw_led7seg(bitmap_t &dest, const rectangle &bounds, const render_color &color, int state); -static void layout_element_draw_led14seg(bitmap_t &dest, const rectangle &bounds, const render_color &color, int state); -static void layout_element_draw_led16seg(bitmap_t &dest, const rectangle &bounds, const render_color &color, int state); -static void layout_element_draw_led14segsc(bitmap_t &dest, const rectangle &bounds, const render_color &color, int state); -static void layout_element_draw_led16segsc(bitmap_t &dest, const rectangle &bounds, const render_color &color, int state); -static void layout_element_draw_dotmatrix(bitmap_t &dest, const rectangle &bounds, const render_color &color, int state); - -/* layout file parsing */ -static layout_element *load_layout_element(running_machine &machine, xml_data_node *elemnode, const char *dirname); -static element_component *load_element_component(running_machine &machine, xml_data_node *compnode, const char *dirname); -static layout_view *load_layout_view(running_machine &machine, xml_data_node *viewnode, layout_element *elemlist); -static view_item *load_view_item(running_machine &machine, xml_data_node *itemnode, layout_element *elemlist); -static bitmap_t *load_component_bitmap(const char *dirname, const char *file, const char *alphafile, int *hasalpha); -static int load_bounds(running_machine &machine, xml_data_node *boundsnode, render_bounds *bounds); -static int load_color(running_machine &machine, xml_data_node *colornode, render_color *color); -static int load_orientation(running_machine &machine, xml_data_node *orientnode, int *orientation); -static void layout_view_free(layout_view *view); -static void layout_element_free(layout_element *element); +const render_screen_list render_target::s_empty_screen_list; -/*************************************************************************** - INLINE FUNCTIONS -***************************************************************************/ +//************************************************************************** +// INLINE HELPERS +//************************************************************************** -/*------------------------------------------------- - gcd - compute the greatest common divisor (GCD) - of two integers using the Euclidean algorithm --------------------------------------------------*/ +//------------------------------------------------- +// gcd - compute the greatest common divisor (GCD) +// of two integers using the Euclidean algorithm +//------------------------------------------------- -INLINE int gcd(int a, int b) +inline int gcd(int a, int b) { while (b != 0) { @@ -195,1215 +159,67 @@ INLINE int gcd(int a, int b) } -/*------------------------------------------------- - reduce_fraction - reduce a fraction by - dividing out common factors --------------------------------------------------*/ +//------------------------------------------------- +// reduce_fraction - reduce a fraction by +// dividing out common factors +//------------------------------------------------- -INLINE void reduce_fraction(int *num, int *den) +inline void reduce_fraction(int &num, int &den) { - int div; + // search the greatest common divisor + int div = gcd(num, den); - /* search the greatest common divisor */ - div = gcd(*num, *den); - - /* reduce the fraction if a common divisor has been found */ + // reduce the fraction if a common divisor has been found if (div > 1) { - *num /= div; - *den /= div; - } -} - - -/*------------------------------------------------- - copy_string - make a copy of a string --------------------------------------------------*/ - -INLINE const char *copy_string(const char *string) -{ - char *newstring = global_alloc_array(char, strlen(string) + 1); - strcpy(newstring, string); - return newstring; -} - - - -/*************************************************************************** - LAYOUT VIEWS -***************************************************************************/ - -/*------------------------------------------------- - layout_view_recompute - recompute the bounds - and aspect ratio of a view and all of its - contained items --------------------------------------------------*/ - -void layout_view_recompute(layout_view *view, int layerconfig) -{ - render_bounds target_bounds; - float xscale, yscale; - float xoffs, yoffs; - int scrfirst = TRUE; - int first = TRUE; - int layer; - - /* reset the bounds */ - view->bounds.x0 = view->bounds.y0 = view->bounds.x1 = view->bounds.y1 = 0.0f; - view->scrbounds.x0 = view->scrbounds.y0 = view->scrbounds.x1 = view->scrbounds.y1 = 0.0f; - view->screens = 0; - - /* loop over all layers */ - for (layer = 0; layer < ITEM_LAYER_MAX; layer++) - { - static const int layer_mask[ITEM_LAYER_MAX] = { LAYER_CONFIG_ENABLE_BACKDROP, 0, LAYER_CONFIG_ENABLE_OVERLAY, LAYER_CONFIG_ENABLE_BEZEL }; - - /* determine if this layer should be visible */ - view->layenabled[layer] = (layer_mask[layer] == 0 || (layerconfig & layer_mask[layer])); - - /* only do it if requested */ - if (view->layenabled[layer]) - { - view_item *item; - - for (item = view->itemlist[layer]; item != NULL; item = item->next) - { - /* accumulate bounds */ - if (first) - view->bounds = item->rawbounds; - else - union_render_bounds(&view->bounds, &item->rawbounds); - first = FALSE; - - /* accumulate screen bounds */ - if (item->element == NULL) - { - if (scrfirst) - view->scrbounds = item->rawbounds; - else - union_render_bounds(&view->scrbounds, &item->rawbounds); - scrfirst = FALSE; - - /* accumulate the screens in use while we're scanning */ - view->screens |= 1 << item->index; - } - } - } - } - - /* if we have an explicit bounds, override it */ - if (view->expbounds.x1 > view->expbounds.x0) - view->bounds = view->expbounds; - - /* compute the aspect ratio of the view */ - view->aspect = (view->bounds.x1 - view->bounds.x0) / (view->bounds.y1 - view->bounds.y0); - view->scraspect = (view->scrbounds.x1 - view->scrbounds.x0) / (view->scrbounds.y1 - view->scrbounds.y0); - - /* if we're handling things normally, the target bounds are (0,0)-(1,1) */ - if (!(layerconfig & LAYER_CONFIG_ZOOM_TO_SCREEN) || view->screens == 0) - { - target_bounds.x0 = target_bounds.y0 = 0.0f; - target_bounds.x1 = target_bounds.y1 = 1.0f; - } - - /* if we're cropping, we want the screen area to fill (0,0)-(1,1) */ - else - { - float targwidth = (view->bounds.x1 - view->bounds.x0) / (view->scrbounds.x1 - view->scrbounds.x0); - float targheight = (view->bounds.y1 - view->bounds.y0) / (view->scrbounds.y1 - view->scrbounds.y0); - target_bounds.x0 = (view->bounds.x0 - view->scrbounds.x0) / (view->bounds.x1 - view->bounds.x0) * targwidth; - target_bounds.y0 = (view->bounds.y0 - view->scrbounds.y0) / (view->bounds.y1 - view->bounds.y0) * targheight; - target_bounds.x1 = target_bounds.x0 + targwidth; - target_bounds.y1 = target_bounds.y0 + targheight; - } - - /* determine the scale/offset for normalization */ - xoffs = view->bounds.x0; - yoffs = view->bounds.y0; - xscale = (target_bounds.x1 - target_bounds.x0) / (view->bounds.x1 - view->bounds.x0); - yscale = (target_bounds.y1 - target_bounds.y0) / (view->bounds.y1 - view->bounds.y0); - - /* normalize all the item bounds */ - for (layer = 0; layer < ITEM_LAYER_MAX; layer++) - { - view_item *item; - - /* adjust the bounds for each item */ - for (item = view->itemlist[layer]; item; item = item->next) - { - item->bounds.x0 = target_bounds.x0 + (item->rawbounds.x0 - xoffs) * xscale; - item->bounds.x1 = target_bounds.x0 + (item->rawbounds.x1 - xoffs) * xscale; - item->bounds.y0 = target_bounds.y0 + (item->rawbounds.y0 - yoffs) * yscale; - item->bounds.y1 = target_bounds.y0 + (item->rawbounds.y1 - yoffs) * yscale; - } + num /= div; + den /= div; } } -/*************************************************************************** - LAYOUT ELEMENTS -***************************************************************************/ - -/*------------------------------------------------- - layout_element_scale - scale an element by - rendering all the components at the - appropriate resolution --------------------------------------------------*/ - -static void layout_element_scale(bitmap_t &dest, const bitmap_t &source, const rectangle &sbounds, void *param) -{ - element_texture *elemtex = (element_texture *)param; - element_component *component; - - /* iterate over components that are part of the current state */ - for (component = elemtex->element->complist; component != NULL; component = component->next) - if (component->state == -1 || component->state == elemtex->state) - { - rectangle bounds; - - /* get the local scaled bounds */ - bounds.min_x = render_round_nearest(component->bounds.x0 * dest.width); - bounds.min_y = render_round_nearest(component->bounds.y0 * dest.height); - bounds.max_x = render_round_nearest(component->bounds.x1 * dest.width); - bounds.max_y = render_round_nearest(component->bounds.y1 * dest.height); - - /* based on the component type, add to the texture */ - switch (component->type) - { - case COMPONENT_TYPE_IMAGE: - if (component->bitmap == NULL) - component->bitmap = load_component_bitmap(component->dirname, component->imagefile, component->alphafile, &component->hasalpha); - render_resample_argb_bitmap_hq( - BITMAP_ADDR32(&dest, bounds.min_y, bounds.min_x), - dest.rowpixels, - bounds.max_x - bounds.min_x, - bounds.max_y - bounds.min_y, - component->bitmap, NULL, &component->color); - break; - - case COMPONENT_TYPE_RECT: - layout_element_draw_rect(dest, bounds, component->color); - break; - - case COMPONENT_TYPE_DISK: - layout_element_draw_disk(dest, bounds, component->color); - break; - - case COMPONENT_TYPE_TEXT: - layout_element_draw_text(*elemtex->element->machine, dest, bounds, component->color, component->string); - break; - - case COMPONENT_TYPE_LED7SEG: - layout_element_draw_led7seg(dest, bounds, component->color, elemtex->state); - break; - - case COMPONENT_TYPE_LED14SEG: - layout_element_draw_led14seg(dest, bounds, component->color, elemtex->state); - break; - - case COMPONENT_TYPE_LED16SEG: - layout_element_draw_led16seg(dest, bounds, component->color, elemtex->state); - break; - - case COMPONENT_TYPE_LED14SEGSC: - layout_element_draw_led14segsc(dest, bounds, component->color, elemtex->state); - break; - - case COMPONENT_TYPE_LED16SEGSC: - layout_element_draw_led16segsc(dest, bounds, component->color, elemtex->state); - break; - - case COMPONENT_TYPE_DOTMATRIX: - layout_element_draw_dotmatrix(dest, bounds, component->color, elemtex->state); - break; - } - } -} - - -/*------------------------------------------------- - layout_element_draw_rect - draw a rectangle - in the specified color --------------------------------------------------*/ - -static void layout_element_draw_rect(bitmap_t &dest, const rectangle &bounds, const render_color &color) -{ - UINT32 r, g, b, inva; - UINT32 x, y; - - /* compute premultiplied colors */ - r = color.r * color.a * 255.0; - g = color.g * color.a * 255.0; - b = color.b * color.a * 255.0; - inva = (1.0f - color.a) * 255.0; - - /* iterate over X and Y */ - for (y = bounds.min_y; y < bounds.max_y; y++) - for (x = bounds.min_x; x < bounds.max_x; x++) - { - UINT32 finalr = r; - UINT32 finalg = g; - UINT32 finalb = b; - - /* if we're translucent, add in the destination pixel contribution */ - if (inva > 0) - { - UINT32 dpix = *BITMAP_ADDR32(&dest, y, x); - finalr += (RGB_RED(dpix) * inva) >> 8; - finalg += (RGB_GREEN(dpix) * inva) >> 8; - finalb += (RGB_BLUE(dpix) * inva) >> 8; - } - - /* store the target pixel, dividing the RGBA values by the overall scale factor */ - *BITMAP_ADDR32(&dest, y, x) = MAKE_ARGB(0xff, finalr, finalg, finalb); - } -} - - -/*------------------------------------------------- - layout_element_draw_disk - draw an ellipse - in the specified color --------------------------------------------------*/ - -static void layout_element_draw_disk(bitmap_t &dest, const rectangle &bounds, const render_color &color) -{ - float xcenter, ycenter; - float xradius, yradius, ooyradius2; - UINT32 r, g, b, inva; - UINT32 x, y; - - /* compute premultiplied colors */ - r = color.r * color.a * 255.0; - g = color.g * color.a * 255.0; - b = color.b * color.a * 255.0; - inva = (1.0f - color.a) * 255.0; - - /* find the center */ - xcenter = (float)(bounds.min_x + bounds.max_x) * 0.5f; - ycenter = (float)(bounds.min_y + bounds.max_y) * 0.5f; - xradius = (float)(bounds.max_x - bounds.min_x) * 0.5f; - yradius = (float)(bounds.max_y - bounds.min_y) * 0.5f; - ooyradius2 = 1.0f / (yradius * yradius); - - /* iterate over y */ - for (y = bounds.min_y; y < bounds.max_y; y++) - { - float ycoord = ycenter - ((float)y + 0.5f); - float xval = xradius * sqrt(1.0f - (ycoord * ycoord) * ooyradius2); - INT32 left, right; - - /* compute left/right coordinates */ - left = (INT32)(xcenter - xval + 0.5f); - right = (INT32)(xcenter + xval + 0.5f); - - /* draw this scanline */ - for (x = left; x < right; x++) - { - UINT32 finalr = r; - UINT32 finalg = g; - UINT32 finalb = b; - - /* if we're translucent, add in the destination pixel contribution */ - if (inva > 0) - { - UINT32 dpix = *BITMAP_ADDR32(&dest, y, x); - finalr += (RGB_RED(dpix) * inva) >> 8; - finalg += (RGB_GREEN(dpix) * inva) >> 8; - finalb += (RGB_BLUE(dpix) * inva) >> 8; - } - - /* store the target pixel, dividing the RGBA values by the overall scale factor */ - *BITMAP_ADDR32(&dest, y, x) = MAKE_ARGB(0xff, finalr, finalg, finalb); - } - } -} - - -/*------------------------------------------------- - layout_element_draw_text - draw text in the - specified color --------------------------------------------------*/ - -static void layout_element_draw_text(running_machine &machine, bitmap_t &dest, const rectangle &bounds, const render_color &color, const char *string) -{ - render_font *font = render_font_alloc(machine, NULL); - bitmap_t *tempbitmap; - UINT32 r, g, b, a; - float aspect = 1.0f; - INT32 curx, width; - const char *s; - - /* compute premultiplied colors */ - r = color.r * 255.0; - g = color.g * 255.0; - b = color.b * 255.0; - a = color.a * 255.0; - - /* get the width of the string */ - while (1) - { - width = render_font_get_string_width(font, bounds.max_y - bounds.min_y, aspect, string); - if (width < bounds.max_x - bounds.min_x) - break; - aspect *= 0.9f; - } - curx = bounds.min_x + (bounds.max_x - bounds.min_x - width) / 2; - - /* allocate a temporary bitmap */ - tempbitmap = global_alloc(bitmap_t(dest.width, dest.height, BITMAP_FORMAT_ARGB32)); - - /* loop over characters */ - for (s = string; *s != 0; s++) - { - rectangle chbounds; - int x, y; - - /* get the font bitmap */ - render_font_get_scaled_bitmap_and_bounds(font, tempbitmap, bounds.max_y - bounds.min_y, aspect, *s, &chbounds); - - /* copy the data into the target */ - for (y = 0; y < chbounds.max_y - chbounds.min_y; y++) - { - int effy = bounds.min_y + y; - if (effy >= bounds.min_y && effy <= bounds.max_y) - { - UINT32 *src = BITMAP_ADDR32(tempbitmap, y, 0); - UINT32 *d = BITMAP_ADDR32(&dest, effy, 0); - for (x = 0; x < chbounds.max_x - chbounds.min_x; x++) - { - int effx = curx + x + chbounds.min_x; - if (effx >= bounds.min_x && effx <= bounds.max_x) - { - UINT32 spix = RGB_ALPHA(src[x]); - if (spix != 0) - { - UINT32 dpix = d[effx]; - UINT32 ta, tr, tg, tb; - - ta = (a * (spix + 1)) >> 8; - tr = (r * ta + RGB_RED(dpix) * (0x100 - ta)) >> 8; - tg = (g * ta + RGB_GREEN(dpix) * (0x100 - ta)) >> 8; - tb = (b * ta + RGB_BLUE(dpix) * (0x100 - ta)) >> 8; - d[effx] = MAKE_ARGB(0xff, tr, tg, tb); - } - } - } - } - } - - /* advance in the X direction */ - curx += render_font_get_char_width(font, bounds.max_y - bounds.min_y, aspect, *s); - } - - /* free the temporary bitmap and font */ - global_free(tempbitmap); - render_font_free(font); -} - - -/*------------------------------------------------- - draw_segment_horizontal_caps - draw a - horizontal LED segment with definable end - and start points --------------------------------------------------*/ - -static void draw_segment_horizontal_caps(bitmap_t &dest, int minx, int maxx, int midy, int width, int caps, rgb_t color) -{ - int x, y; - - /* loop over the width of the segment */ - for (y = 0; y < width / 2; y++) - { - UINT32 *d0 = BITMAP_ADDR32(&dest, midy - y, 0); - UINT32 *d1 = BITMAP_ADDR32(&dest, midy + y, 0); - int ty = (y < width / 8) ? width / 8 : y; - - /* loop over the length of the segment */ - for (x = minx + ((caps & LINE_CAP_START) ? ty : 0); x < maxx - ((caps & LINE_CAP_END) ? ty : 0); x++) - d0[x] = d1[x] = color; - } -} - - -/*------------------------------------------------- - draw_segment_horizontal - draw a horizontal - LED segment --------------------------------------------------*/ - -static void draw_segment_horizontal(bitmap_t &dest, int minx, int maxx, int midy, int width, rgb_t color) -{ - draw_segment_horizontal_caps(dest, minx, maxx, midy, width, LINE_CAP_START | LINE_CAP_END, color); -} - - -/*------------------------------------------------- - draw_segment_vertical_caps - draw a - vertical LED segment with definable end - and start points --------------------------------------------------*/ - -static void draw_segment_vertical_caps(bitmap_t &dest, int miny, int maxy, int midx, int width, int caps, rgb_t color) -{ - int x, y; - - /* loop over the width of the segment */ - for (x = 0; x < width / 2; x++) - { - UINT32 *d0 = BITMAP_ADDR32(&dest, 0, midx - x); - UINT32 *d1 = BITMAP_ADDR32(&dest, 0, midx + x); - int tx = (x < width / 8) ? width / 8 : x; - - /* loop over the length of the segment */ - for (y = miny + ((caps & LINE_CAP_START) ? tx : 0); y < maxy - ((caps & LINE_CAP_END) ? tx : 0); y++) - d0[y * dest.rowpixels] = d1[y * dest.rowpixels] = color; - } -} - - -/*------------------------------------------------- - draw_segment_vertical - draw a vertical - LED segment --------------------------------------------------*/ - -static void draw_segment_vertical(bitmap_t &dest, int miny, int maxy, int midx, int width, rgb_t color) -{ - draw_segment_vertical_caps(dest, miny, maxy, midx, width, LINE_CAP_START | LINE_CAP_END, color); -} - - -/*------------------------------------------------- - draw_segment_diagonal_1 - draw a diagonal - LED segment that looks like this: / --------------------------------------------------*/ - -static void draw_segment_diagonal_1(bitmap_t &dest, int minx, int maxx, int miny, int maxy, int width, rgb_t color) -{ - int x, y; - float ratio; - - /* compute parameters */ - width *= 1.5; - ratio = (maxy - miny - width) / (float)(maxx - minx); - - /* draw line */ - for (x = minx; x < maxx; x++) - if (x >= 0 && x < dest.width) - { - UINT32 *d = BITMAP_ADDR32(&dest, 0, x); - int step = (x - minx) * ratio; - - for (y = maxy - width - step; y < maxy - step; y++) - if (y >= 0 && y < dest.height) - { - d[y * dest.rowpixels] = color; - } - } -} - - -/*------------------------------------------------- - draw_segment_diagonal_2 - draw a diagonal - LED segment that looks like this: \ --------------------------------------------------*/ - -static void draw_segment_diagonal_2(bitmap_t &dest, int minx, int maxx, int miny, int maxy, int width, rgb_t color) -{ - int x, y; - float ratio; - - /* compute parameters */ - width *= 1.5; - ratio = (maxy - miny - width) / (float)(maxx - minx); - - /* draw line */ - for (x = minx; x < maxx; x++) - if (x >= 0 && x < dest.width) - { - UINT32 *d = BITMAP_ADDR32(&dest, 0, x); - int step = (x - minx) * ratio; - - for (y = miny + step; y < miny + step + width; y++) - if (y >= 0 && y < dest.height) - { - d[y * dest.rowpixels] = color; - } - } -} - - -/*------------------------------------------------- - draw_segment_decimal - draw a decimal point --------------------------------------------------*/ - -static void draw_segment_decimal(bitmap_t &dest, int midx, int midy, int width, rgb_t color) -{ - float ooradius2; - UINT32 x, y; - - /* compute parameters */ - width /= 2; - ooradius2 = 1.0f / (float)(width * width); - - /* iterate over y */ - for (y = 0; y <= width; y++) - { - UINT32 *d0 = BITMAP_ADDR32(&dest, midy - y, 0); - UINT32 *d1 = BITMAP_ADDR32(&dest, midy + y, 0); - float xval = width * sqrt(1.0f - (float)(y * y) * ooradius2); - INT32 left, right; - - /* compute left/right coordinates */ - left = midx - (INT32)(xval + 0.5f); - right = midx + (INT32)(xval + 0.5f); - - /* draw this scanline */ - for (x = left; x < right; x++) - d0[x] = d1[x] = color; - } -} - -/*------------------------------------------------- - draw_segment_comma - draw a comma tail --------------------------------------------------*/ -#if 0 -static void draw_segment_comma(bitmap_t &dest, int minx, int maxx, int miny, int maxy, int width, rgb_t color) -{ - int x, y; - float ratio; - - /* compute parameters */ - width *= 1.5; - ratio = (maxy - miny - width) / (float)(maxx - minx); - - /* draw line */ - for (x = minx; x < maxx; x++) - { - UINT32 *d = BITMAP_ADDR32(&dest, 0, x); - int step = (x - minx) * ratio; - - for (y = maxy; y < maxy - width - step; y--) - { - d[y * dest.rowpixels] = color; - } - } -} -#endif - - -/*------------------------------------------------- - apply_skew - apply skew to a bitmap_t --------------------------------------------------*/ - -static void apply_skew(bitmap_t &dest, int skewwidth) -{ - int x, y; - - for (y = 0; y < dest.height; y++) - { - UINT32 *destrow = BITMAP_ADDR32(&dest, y, 0); - int offs = skewwidth * (dest.height - y) / dest.height; - for (x = dest.width - skewwidth - 1; x >= 0; x--) - destrow[x + offs] = destrow[x]; - for (x = 0; x < offs; x++) - destrow[x] = 0; - } -} - - -/*------------------------------------------------- - layout_element_draw_led7seg - draw a - 7-segment LCD --------------------------------------------------*/ - -static void layout_element_draw_led7seg(bitmap_t &dest, const rectangle &bounds, const render_color &color, int pattern) -{ - const rgb_t onpen = MAKE_ARGB(0xff,0xff,0xff,0xff); - const rgb_t offpen = MAKE_ARGB(0xff,0x20,0x20,0x20); - int bmwidth, bmheight, segwidth, skewwidth; - bitmap_t *tempbitmap; - - /* sizes for computation */ - bmwidth = 250; - bmheight = 400; - segwidth = 40; - skewwidth = 40; - - /* allocate a temporary bitmap for drawing */ - tempbitmap = global_alloc(bitmap_t(bmwidth + skewwidth, bmheight, BITMAP_FORMAT_ARGB32)); - bitmap_fill(tempbitmap, NULL, MAKE_ARGB(0xff,0x00,0x00,0x00)); - - /* top bar */ - draw_segment_horizontal(*tempbitmap, 0 + 2*segwidth/3, bmwidth - 2*segwidth/3, 0 + segwidth/2, segwidth, (pattern & (1 << 0)) ? onpen : offpen); - - /* top-right bar */ - draw_segment_vertical(*tempbitmap, 0 + 2*segwidth/3, bmheight/2 - segwidth/3, bmwidth - segwidth/2, segwidth, (pattern & (1 << 1)) ? onpen : offpen); - - /* bottom-right bar */ - draw_segment_vertical(*tempbitmap, bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, bmwidth - segwidth/2, segwidth, (pattern & (1 << 2)) ? onpen : offpen); - - /* bottom bar */ - draw_segment_horizontal(*tempbitmap, 0 + 2*segwidth/3, bmwidth - 2*segwidth/3, bmheight - segwidth/2, segwidth, (pattern & (1 << 3)) ? onpen : offpen); - - /* bottom-left bar */ - draw_segment_vertical(*tempbitmap, bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, 0 + segwidth/2, segwidth, (pattern & (1 << 4)) ? onpen : offpen); - - /* top-left bar */ - draw_segment_vertical(*tempbitmap, 0 + 2*segwidth/3, bmheight/2 - segwidth/3, 0 + segwidth/2, segwidth, (pattern & (1 << 5)) ? onpen : offpen); - - /* middle bar */ - draw_segment_horizontal(*tempbitmap, 0 + 2*segwidth/3, bmwidth - 2*segwidth/3, bmheight/2, segwidth, (pattern & (1 << 6)) ? onpen : offpen); - - /* apply skew */ - apply_skew(*tempbitmap, 40); - - /* decimal point */ - draw_segment_decimal(*tempbitmap, bmwidth + segwidth/2, bmheight - segwidth/2, segwidth, (pattern & (1 << 7)) ? onpen : offpen); - - /* resample to the target size */ - render_resample_argb_bitmap_hq(dest.base, dest.rowpixels, dest.width, dest.height, tempbitmap, NULL, &color); - - global_free(tempbitmap); -} - - -/*------------------------------------------------- - layout_element_draw_led14seg - draw a - 14-segment LCD --------------------------------------------------*/ - -static void layout_element_draw_led14seg(bitmap_t &dest, const rectangle &bounds, const render_color &color, int pattern) -{ - const rgb_t onpen = MAKE_ARGB(0xff, 0xff, 0xff, 0xff); - const rgb_t offpen = MAKE_ARGB(0xff, 0x20, 0x20, 0x20); - int bmwidth, bmheight, segwidth, skewwidth; - bitmap_t *tempbitmap; - - /* sizes for computation */ - bmwidth = 250; - bmheight = 400; - segwidth = 40; - skewwidth = 40; - - /* allocate a temporary bitmap for drawing */ - tempbitmap = global_alloc(bitmap_t(bmwidth + skewwidth, bmheight, BITMAP_FORMAT_ARGB32)); - bitmap_fill(tempbitmap, NULL, MAKE_ARGB(0xff, 0x00, 0x00, 0x00)); - - /* top bar */ - draw_segment_horizontal(*tempbitmap, - 0 + 2*segwidth/3, bmwidth - 2*segwidth/3, 0 + segwidth/2, - segwidth, (pattern & (1 << 0)) ? onpen : offpen); - - /* right-top bar */ - draw_segment_vertical(*tempbitmap, - 0 + 2*segwidth/3, bmheight/2 - segwidth/3, bmwidth - segwidth/2, - segwidth, (pattern & (1 << 1)) ? onpen : offpen); - - /* right-bottom bar */ - draw_segment_vertical(*tempbitmap, - bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, bmwidth - segwidth/2, - segwidth, (pattern & (1 << 2)) ? onpen : offpen); - - /* bottom bar */ - draw_segment_horizontal(*tempbitmap, - 0 + 2*segwidth/3, bmwidth - 2*segwidth/3, bmheight - segwidth/2, - segwidth, (pattern & (1 << 3)) ? onpen : offpen); - - /* left-bottom bar */ - draw_segment_vertical(*tempbitmap, - bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, 0 + segwidth/2, - segwidth, (pattern & (1 << 4)) ? onpen : offpen); - - /* left-top bar */ - draw_segment_vertical(*tempbitmap, - 0 + 2*segwidth/3, bmheight/2 - segwidth/3, 0 + segwidth/2, - segwidth, (pattern & (1 << 5)) ? onpen : offpen); - - /* horizontal-middle-left bar */ - draw_segment_horizontal_caps(*tempbitmap, - 0 + 2*segwidth/3, bmwidth/2 - segwidth/10, bmheight/2, - segwidth, LINE_CAP_START, (pattern & (1 << 6)) ? onpen : offpen); - - /* horizontal-middle-right bar */ - draw_segment_horizontal_caps(*tempbitmap, - 0 + bmwidth/2 + segwidth/10, bmwidth - 2*segwidth/3, bmheight/2, - segwidth, LINE_CAP_END, (pattern & (1 << 7)) ? onpen : offpen); - - /* vertical-middle-top bar */ - draw_segment_vertical_caps(*tempbitmap, - 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3, bmwidth/2, - segwidth, LINE_CAP_NONE, (pattern & (1 << 8)) ? onpen : offpen); - - /* vertical-middle-bottom bar */ - draw_segment_vertical_caps(*tempbitmap, - bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3, bmwidth/2, - segwidth, LINE_CAP_NONE, (pattern & (1 << 9)) ? onpen : offpen); - - /* diagonal-left-bottom bar */ - draw_segment_diagonal_1(*tempbitmap, - 0 + segwidth + segwidth/5, bmwidth/2 - segwidth/2 - segwidth/5, - bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3, - segwidth, (pattern & (1 << 10)) ? onpen : offpen); - - /* diagonal-left-top bar */ - draw_segment_diagonal_2(*tempbitmap, - 0 + segwidth + segwidth/5, bmwidth/2 - segwidth/2 - segwidth/5, - 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3, - segwidth, (pattern & (1 << 11)) ? onpen : offpen); - - /* diagonal-right-top bar */ - draw_segment_diagonal_1(*tempbitmap, - bmwidth/2 + segwidth/2 + segwidth/5, bmwidth - segwidth - segwidth/5, - 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3, - segwidth, (pattern & (1 << 12)) ? onpen : offpen); - - /* diagonal-right-bottom bar */ - draw_segment_diagonal_2(*tempbitmap, - bmwidth/2 + segwidth/2 + segwidth/5, bmwidth - segwidth - segwidth/5, - bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3, - segwidth, (pattern & (1 << 13)) ? onpen : offpen); - - /* apply skew */ - apply_skew(*tempbitmap, 40); - - /* resample to the target size */ - render_resample_argb_bitmap_hq(dest.base, dest.rowpixels, dest.width, dest.height, tempbitmap, NULL, &color); - - global_free(tempbitmap); -} - - -/*------------------------------------------------- - layout_element_draw_led14segsc - draw a - 14-segment LCD with semicolon (2 extra segments) --------------------------------------------------*/ - -static void layout_element_draw_led14segsc(bitmap_t &dest, const rectangle &bounds, const render_color &color, int pattern) -{ - const rgb_t onpen = MAKE_ARGB(0xff, 0xff, 0xff, 0xff); - const rgb_t offpen = MAKE_ARGB(0xff, 0x20, 0x20, 0x20); - int bmwidth, bmheight, segwidth, skewwidth; - bitmap_t *tempbitmap; - - /* sizes for computation */ - bmwidth = 250; - bmheight = 400; - segwidth = 40; - skewwidth = 40; - - /* allocate a temporary bitmap for drawing, adding some extra space for the tail */ - tempbitmap = global_alloc(bitmap_t(bmwidth + skewwidth, bmheight + segwidth, BITMAP_FORMAT_ARGB32)); - bitmap_fill(tempbitmap, NULL, MAKE_ARGB(0xff, 0x00, 0x00, 0x00)); - - /* top bar */ - draw_segment_horizontal(*tempbitmap, - 0 + 2*segwidth/3, bmwidth - 2*segwidth/3, 0 + segwidth/2, - segwidth, (pattern & (1 << 0)) ? onpen : offpen); - - /* right-top bar */ - draw_segment_vertical(*tempbitmap, - 0 + 2*segwidth/3, bmheight/2 - segwidth/3, bmwidth - segwidth/2, - segwidth, (pattern & (1 << 1)) ? onpen : offpen); - - /* right-bottom bar */ - draw_segment_vertical(*tempbitmap, - bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, bmwidth - segwidth/2, - segwidth, (pattern & (1 << 2)) ? onpen : offpen); - - /* bottom bar */ - draw_segment_horizontal(*tempbitmap, - 0 + 2*segwidth/3, bmwidth - 2*segwidth/3, bmheight - segwidth/2, - segwidth, (pattern & (1 << 3)) ? onpen : offpen); - - /* left-bottom bar */ - draw_segment_vertical(*tempbitmap, - bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, 0 + segwidth/2, - segwidth, (pattern & (1 << 4)) ? onpen : offpen); - - /* left-top bar */ - draw_segment_vertical(*tempbitmap, - 0 + 2*segwidth/3, bmheight/2 - segwidth/3, 0 + segwidth/2, - segwidth, (pattern & (1 << 5)) ? onpen : offpen); - - /* horizontal-middle-left bar */ - draw_segment_horizontal_caps(*tempbitmap, - 0 + 2*segwidth/3, bmwidth/2 - segwidth/10, bmheight/2, - segwidth, LINE_CAP_START, (pattern & (1 << 6)) ? onpen : offpen); - - /* horizontal-middle-right bar */ - draw_segment_horizontal_caps(*tempbitmap, - 0 + bmwidth/2 + segwidth/10, bmwidth - 2*segwidth/3, bmheight/2, - segwidth, LINE_CAP_END, (pattern & (1 << 7)) ? onpen : offpen); - - /* vertical-middle-top bar */ - draw_segment_vertical_caps(*tempbitmap, - 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3, bmwidth/2, - segwidth, LINE_CAP_NONE, (pattern & (1 << 8)) ? onpen : offpen); - - /* vertical-middle-bottom bar */ - draw_segment_vertical_caps(*tempbitmap, - bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3, bmwidth/2, - segwidth, LINE_CAP_NONE, (pattern & (1 << 9)) ? onpen : offpen); - - /* diagonal-left-bottom bar */ - draw_segment_diagonal_1(*tempbitmap, - 0 + segwidth + segwidth/5, bmwidth/2 - segwidth/2 - segwidth/5, - bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3, - segwidth, (pattern & (1 << 10)) ? onpen : offpen); - - /* diagonal-left-top bar */ - draw_segment_diagonal_2(*tempbitmap, - 0 + segwidth + segwidth/5, bmwidth/2 - segwidth/2 - segwidth/5, - 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3, - segwidth, (pattern & (1 << 11)) ? onpen : offpen); - - /* diagonal-right-top bar */ - draw_segment_diagonal_1(*tempbitmap, - bmwidth/2 + segwidth/2 + segwidth/5, bmwidth - segwidth - segwidth/5, - 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3, - segwidth, (pattern & (1 << 12)) ? onpen : offpen); - - /* diagonal-right-bottom bar */ - draw_segment_diagonal_2(*tempbitmap, - bmwidth/2 + segwidth/2 + segwidth/5, bmwidth - segwidth - segwidth/5, - bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3, - segwidth, (pattern & (1 << 13)) ? onpen : offpen); - - /* apply skew */ - apply_skew(*tempbitmap, 40); - - /* decimal point */ - draw_segment_decimal(*tempbitmap, bmwidth + segwidth/2, bmheight - segwidth/2, segwidth, (pattern & (1 << 14)) ? onpen : offpen); - - /* comma tail */ - draw_segment_diagonal_1(*tempbitmap, - bmwidth - (segwidth/2), bmwidth + segwidth, - bmheight - (segwidth), bmheight + segwidth*1.5, - segwidth/2, (pattern & (1 << 15)) ? onpen : offpen); - - /* resample to the target size */ - render_resample_argb_bitmap_hq(dest.base, dest.rowpixels, dest.width, dest.height, tempbitmap, NULL, &color); - - global_free(tempbitmap); -} - - -/*------------------------------------------------- - layout_element_draw_led16seg - draw a - 16-segment LCD --------------------------------------------------*/ - -static void layout_element_draw_led16seg(bitmap_t &dest, const rectangle &bounds, const render_color &color, int pattern) -{ - const rgb_t onpen = MAKE_ARGB(0xff, 0xff, 0xff, 0xff); - const rgb_t offpen = MAKE_ARGB(0xff, 0x20, 0x20, 0x20); - int bmwidth, bmheight, segwidth, skewwidth; - bitmap_t *tempbitmap; - - /* sizes for computation */ - bmwidth = 250; - bmheight = 400; - segwidth = 40; - skewwidth = 40; - - /* allocate a temporary bitmap for drawing */ - tempbitmap = global_alloc(bitmap_t(bmwidth + skewwidth, bmheight, BITMAP_FORMAT_ARGB32)); - bitmap_fill(tempbitmap, NULL, MAKE_ARGB(0xff, 0x00, 0x00, 0x00)); - - /* top-left bar */ - draw_segment_horizontal_caps(*tempbitmap, - 0 + 2*segwidth/3, bmwidth/2 - segwidth/10, 0 + segwidth/2, - segwidth, LINE_CAP_START, (pattern & (1 << 0)) ? onpen : offpen); - - /* top-right bar */ - draw_segment_horizontal_caps(*tempbitmap, - 0 + bmwidth/2 + segwidth/10, bmwidth - 2*segwidth/3, 0 + segwidth/2, - segwidth, LINE_CAP_END, (pattern & (1 << 1)) ? onpen : offpen); - - /* right-top bar */ - draw_segment_vertical(*tempbitmap, - 0 + 2*segwidth/3, bmheight/2 - segwidth/3, bmwidth - segwidth/2, - segwidth, (pattern & (1 << 2)) ? onpen : offpen); - - /* right-bottom bar */ - draw_segment_vertical(*tempbitmap, - bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, bmwidth - segwidth/2, - segwidth, (pattern & (1 << 3)) ? onpen : offpen); - - /* bottom-right bar */ - draw_segment_horizontal_caps(*tempbitmap, - 0 + bmwidth/2 + segwidth/10, bmwidth - 2*segwidth/3, bmheight - segwidth/2, - segwidth, LINE_CAP_END, (pattern & (1 << 4)) ? onpen : offpen); - - /* bottom-left bar */ - draw_segment_horizontal_caps(*tempbitmap, - 0 + 2*segwidth/3, bmwidth/2 - segwidth/10, bmheight - segwidth/2, - segwidth, LINE_CAP_START, (pattern & (1 << 5)) ? onpen : offpen); - - /* left-bottom bar */ - draw_segment_vertical(*tempbitmap, - bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, 0 + segwidth/2, - segwidth, (pattern & (1 << 6)) ? onpen : offpen); - - /* left-top bar */ - draw_segment_vertical(*tempbitmap, - 0 + 2*segwidth/3, bmheight/2 - segwidth/3, 0 + segwidth/2, - segwidth, (pattern & (1 << 7)) ? onpen : offpen); - - /* horizontal-middle-left bar */ - draw_segment_horizontal_caps(*tempbitmap, - 0 + 2*segwidth/3, bmwidth/2 - segwidth/10, bmheight/2, - segwidth, LINE_CAP_START, (pattern & (1 << 8)) ? onpen : offpen); - - /* horizontal-middle-right bar */ - draw_segment_horizontal_caps(*tempbitmap, - 0 + bmwidth/2 + segwidth/10, bmwidth - 2*segwidth/3, bmheight/2, - segwidth, LINE_CAP_END, (pattern & (1 << 9)) ? onpen : offpen); - - /* vertical-middle-top bar */ - draw_segment_vertical_caps(*tempbitmap, - 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3, bmwidth/2, - segwidth, LINE_CAP_NONE, (pattern & (1 << 10)) ? onpen : offpen); - - /* vertical-middle-bottom bar */ - draw_segment_vertical_caps(*tempbitmap, - bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3, bmwidth/2, - segwidth, LINE_CAP_NONE, (pattern & (1 << 11)) ? onpen : offpen); - - /* diagonal-left-bottom bar */ - draw_segment_diagonal_1(*tempbitmap, - 0 + segwidth + segwidth/5, bmwidth/2 - segwidth/2 - segwidth/5, - bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3, - segwidth, (pattern & (1 << 12)) ? onpen : offpen); - - /* diagonal-left-top bar */ - draw_segment_diagonal_2(*tempbitmap, - 0 + segwidth + segwidth/5, bmwidth/2 - segwidth/2 - segwidth/5, - 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3, - segwidth, (pattern & (1 << 13)) ? onpen : offpen); - - /* diagonal-right-top bar */ - draw_segment_diagonal_1(*tempbitmap, - bmwidth/2 + segwidth/2 + segwidth/5, bmwidth - segwidth - segwidth/5, - 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3, - segwidth, (pattern & (1 << 14)) ? onpen : offpen); - - /* diagonal-right-bottom bar */ - draw_segment_diagonal_2(*tempbitmap, - bmwidth/2 + segwidth/2 + segwidth/5, bmwidth - segwidth - segwidth/5, - bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3, - segwidth, (pattern & (1 << 15)) ? onpen : offpen); - - /* apply skew */ - apply_skew(*tempbitmap, 40); - - /* resample to the target size */ - render_resample_argb_bitmap_hq(dest.base, dest.rowpixels, dest.width, dest.height, tempbitmap, NULL, &color); - - global_free(tempbitmap); -} - - -/*------------------------------------------------- - layout_element_draw_led16segsc - draw a - 16-segment LCD with semicolon (2 extra segments) --------------------------------------------------*/ - -static void layout_element_draw_led16segsc(bitmap_t &dest, const rectangle &bounds, const render_color &color, int pattern) -{ - const rgb_t onpen = MAKE_ARGB(0xff, 0xff, 0xff, 0xff); - const rgb_t offpen = MAKE_ARGB(0xff, 0x20, 0x20, 0x20); - int bmwidth, bmheight, segwidth, skewwidth; - bitmap_t *tempbitmap; - - /* sizes for computation */ - bmwidth = 250; - bmheight = 400; - segwidth = 40; - skewwidth = 40; - - /* allocate a temporary bitmap for drawing */ - tempbitmap = global_alloc(bitmap_t(bmwidth + skewwidth, bmheight + segwidth, BITMAP_FORMAT_ARGB32)); - bitmap_fill(tempbitmap, NULL, MAKE_ARGB(0xff, 0x00, 0x00, 0x00)); - - /* top-left bar */ - draw_segment_horizontal_caps(*tempbitmap, - 0 + 2*segwidth/3, bmwidth/2 - segwidth/10, 0 + segwidth/2, - segwidth, LINE_CAP_START, (pattern & (1 << 0)) ? onpen : offpen); - - /* top-right bar */ - draw_segment_horizontal_caps(*tempbitmap, - 0 + bmwidth/2 + segwidth/10, bmwidth - 2*segwidth/3, 0 + segwidth/2, - segwidth, LINE_CAP_END, (pattern & (1 << 1)) ? onpen : offpen); - - /* right-top bar */ - draw_segment_vertical(*tempbitmap, - 0 + 2*segwidth/3, bmheight/2 - segwidth/3, bmwidth - segwidth/2, - segwidth, (pattern & (1 << 2)) ? onpen : offpen); - - /* right-bottom bar */ - draw_segment_vertical(*tempbitmap, - bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, bmwidth - segwidth/2, - segwidth, (pattern & (1 << 3)) ? onpen : offpen); - - /* bottom-right bar */ - draw_segment_horizontal_caps(*tempbitmap, - 0 + bmwidth/2 + segwidth/10, bmwidth - 2*segwidth/3, bmheight - segwidth/2, - segwidth, LINE_CAP_END, (pattern & (1 << 4)) ? onpen : offpen); - - /* bottom-left bar */ - draw_segment_horizontal_caps(*tempbitmap, - 0 + 2*segwidth/3, bmwidth/2 - segwidth/10, bmheight - segwidth/2, - segwidth, LINE_CAP_START, (pattern & (1 << 5)) ? onpen : offpen); - - /* left-bottom bar */ - draw_segment_vertical(*tempbitmap, - bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, 0 + segwidth/2, - segwidth, (pattern & (1 << 6)) ? onpen : offpen); - - /* left-top bar */ - draw_segment_vertical(*tempbitmap, - 0 + 2*segwidth/3, bmheight/2 - segwidth/3, 0 + segwidth/2, - segwidth, (pattern & (1 << 7)) ? onpen : offpen); - - /* horizontal-middle-left bar */ - draw_segment_horizontal_caps(*tempbitmap, - 0 + 2*segwidth/3, bmwidth/2 - segwidth/10, bmheight/2, - segwidth, LINE_CAP_START, (pattern & (1 << 8)) ? onpen : offpen); - - /* horizontal-middle-right bar */ - draw_segment_horizontal_caps(*tempbitmap, - 0 + bmwidth/2 + segwidth/10, bmwidth - 2*segwidth/3, bmheight/2, - segwidth, LINE_CAP_END, (pattern & (1 << 9)) ? onpen : offpen); - - /* vertical-middle-top bar */ - draw_segment_vertical_caps(*tempbitmap, - 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3, bmwidth/2, - segwidth, LINE_CAP_NONE, (pattern & (1 << 10)) ? onpen : offpen); - - /* vertical-middle-bottom bar */ - draw_segment_vertical_caps(*tempbitmap, - bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3, bmwidth/2, - segwidth, LINE_CAP_NONE, (pattern & (1 << 11)) ? onpen : offpen); - - /* diagonal-left-bottom bar */ - draw_segment_diagonal_1(*tempbitmap, - 0 + segwidth + segwidth/5, bmwidth/2 - segwidth/2 - segwidth/5, - bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3, - segwidth, (pattern & (1 << 12)) ? onpen : offpen); - - /* diagonal-left-top bar */ - draw_segment_diagonal_2(*tempbitmap, - 0 + segwidth + segwidth/5, bmwidth/2 - segwidth/2 - segwidth/5, - 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3, - segwidth, (pattern & (1 << 13)) ? onpen : offpen); - - /* diagonal-right-top bar */ - draw_segment_diagonal_1(*tempbitmap, - bmwidth/2 + segwidth/2 + segwidth/5, bmwidth - segwidth - segwidth/5, - 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3, - segwidth, (pattern & (1 << 14)) ? onpen : offpen); - - /* diagonal-right-bottom bar */ - draw_segment_diagonal_2(*tempbitmap, - bmwidth/2 + segwidth/2 + segwidth/5, bmwidth - segwidth - segwidth/5, - bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3, - segwidth, (pattern & (1 << 15)) ? onpen : offpen); - - /* decimal point */ - draw_segment_decimal(*tempbitmap, bmwidth + segwidth/2, bmheight - segwidth/2, segwidth, (pattern & (1 << 16)) ? onpen : offpen); - - /* comma tail */ - draw_segment_diagonal_1(*tempbitmap, - bmwidth - (segwidth/2), bmwidth + segwidth, - bmheight - (segwidth), bmheight + segwidth*1.5, - segwidth/2, (pattern & (1 << 17)) ? onpen : offpen); - - /* apply skew */ - apply_skew(*tempbitmap, 40); - - /* resample to the target size */ - render_resample_argb_bitmap_hq(dest.base, dest.rowpixels, dest.width, dest.height, tempbitmap, NULL, &color); - - global_free(tempbitmap); -} - -/*------------------------------------------------- - layout_element_draw_dotmatrix - draw a - row of 8 dots for a dotmatrix --------------------------------------------------*/ - -static void layout_element_draw_dotmatrix(bitmap_t &dest, const rectangle &bounds, const render_color &color, int pattern) -{ - const rgb_t onpen = MAKE_ARGB(0xff, 0xff, 0xff, 0xff); - const rgb_t offpen = MAKE_ARGB(0xff, 0x20, 0x20, 0x20); - int bmwidth, bmheight, dotwidth, i; - bitmap_t *tempbitmap; - - /* sizes for computation */ - bmwidth = 2000; - bmheight = 300; - dotwidth = 250; - - /* allocate a temporary bitmap for drawing */ - tempbitmap = global_alloc(bitmap_t(bmwidth, bmheight, BITMAP_FORMAT_ARGB32)); - bitmap_fill(tempbitmap, NULL, MAKE_ARGB(0xff, 0x00, 0x00, 0x00)); - - for (i = 0; i < 8; i++) - {// height - draw_segment_decimal(*tempbitmap, ((dotwidth/2 )+ (i * dotwidth)), bmheight/2, dotwidth, (pattern & (1 << i))?onpen:offpen); - } - - /* resample to the target size */ - render_resample_argb_bitmap_hq(dest.base, dest.rowpixels, dest.width, dest.height, tempbitmap, NULL, &color); - - global_free(tempbitmap); -} - - -/*************************************************************************** - LAYOUT FILE PARSING -***************************************************************************/ - -/*------------------------------------------------- - get_variable_value - compute the value of - a variable in an XML attribute --------------------------------------------------*/ +//************************************************************************** +// SHARED PARSING HELPERS +//************************************************************************** + +//------------------------------------------------- +// get_variable_value - compute the value of +// a variable in an XML attribute +//------------------------------------------------- static int get_variable_value(running_machine &machine, const char *string, char **outputptr) { - const screen_device_config *devconfig; - int num, den; char temp[100]; - /* screen 0 parameters */ - for (devconfig = screen_first(machine.m_config); devconfig != NULL; devconfig = screen_next(devconfig)) + // screen 0 parameters + for (const screen_device_config *devconfig = screen_first(machine.m_config); devconfig != NULL; devconfig = screen_next(devconfig)) { int scrnum = machine.m_config.m_devicelist.index(SCREEN, devconfig->tag()); - /* native X aspect factor */ + // native X aspect factor sprintf(temp, "~scr%dnativexaspect~", scrnum); if (!strncmp(string, temp, strlen(temp))) { - num = devconfig->visible_area().max_x + 1 - devconfig->visible_area().min_x; - den = devconfig->visible_area().max_y + 1 - devconfig->visible_area().min_y; - reduce_fraction(&num, &den); + int num = devconfig->visible_area().max_x + 1 - devconfig->visible_area().min_x; + int den = devconfig->visible_area().max_y + 1 - devconfig->visible_area().min_y; + reduce_fraction(num, den); *outputptr += sprintf(*outputptr, "%d", num); return strlen(temp); } - /* native Y aspect factor */ + // native Y aspect factor sprintf(temp, "~scr%dnativeyaspect~", scrnum); if (!strncmp(string, temp, strlen(temp))) { - num = devconfig->visible_area().max_x + 1 - devconfig->visible_area().min_x; - den = devconfig->visible_area().max_y + 1 - devconfig->visible_area().min_y; - reduce_fraction(&num, &den); + int num = devconfig->visible_area().max_x + 1 - devconfig->visible_area().min_x; + int den = devconfig->visible_area().max_y + 1 - devconfig->visible_area().min_y; + reduce_fraction(num, den); *outputptr += sprintf(*outputptr, "%d", den); return strlen(temp); } - /* native width */ + // native width sprintf(temp, "~scr%dwidth~", scrnum); if (!strncmp(string, temp, strlen(temp))) { @@ -1411,7 +227,7 @@ static int get_variable_value(running_machine &machine, const char *string, char return strlen(temp); } - /* native height */ + // native height sprintf(temp, "~scr%dheight~", scrnum); if (!strncmp(string, temp, strlen(temp))) { @@ -1420,42 +236,42 @@ static int get_variable_value(running_machine &machine, const char *string, char } } - /* default: copy the first character and continue */ + // default: copy the first character and continue **outputptr = *string; *outputptr += 1; return 1; } -/*------------------------------------------------- - xml_get_attribute_string_with_subst - analog - to xml_get_attribute_string but with variable - substitution --------------------------------------------------*/ +//------------------------------------------------- +// xml_get_attribute_string_with_subst - analog +// to xml_get_attribute_string but with variable +// substitution +//------------------------------------------------- -static const char *xml_get_attribute_string_with_subst(running_machine &machine, xml_data_node *node, const char *attribute, const char *defvalue) +static const char *xml_get_attribute_string_with_subst(running_machine &machine, xml_data_node &node, const char *attribute, const char *defvalue) { - const char *str = xml_get_attribute_string(node, attribute, NULL); + const char *str = xml_get_attribute_string(&node, attribute, NULL); static char buffer[1000]; - const char *s; - char *d; - /* if nothing, just return the default */ + // if nothing, just return the default if (str == NULL) return defvalue; - /* if no tildes, don't worry */ + // if no tildes, don't worry if (strchr(str, '~') == NULL) return str; - /* make a copy of the string, doing substitutions along the way */ + // make a copy of the string, doing substitutions along the way + const char *s; + char *d; for (s = str, d = buffer; *s != 0; ) { - /* if not a variable, just copy */ + // if not a variable, just copy if (*s != '~') *d++ = *s++; - /* extract the variable */ + // extract the variable else s += get_variable_value(machine, s, &d); } @@ -1464,13 +280,13 @@ static const char *xml_get_attribute_string_with_subst(running_machine &machine, } -/*------------------------------------------------- - xml_get_attribute_int_with_subst - analog - to xml_get_attribute_int but with variable - substitution --------------------------------------------------*/ +//------------------------------------------------- +// xml_get_attribute_int_with_subst - analog +// to xml_get_attribute_int but with variable +// substitution +//------------------------------------------------- -static int xml_get_attribute_int_with_subst(running_machine &machine, xml_data_node *node, const char *attribute, int defvalue) +static int xml_get_attribute_int_with_subst(running_machine &machine, xml_data_node &node, const char *attribute, int defvalue) { const char *string = xml_get_attribute_string_with_subst(machine, node, attribute, NULL); int value; @@ -1487,680 +303,1654 @@ static int xml_get_attribute_int_with_subst(running_machine &machine, xml_data_n } -/*------------------------------------------------- - xml_get_attribute_float_with_subst - analog - to xml_get_attribute_float but with variable - substitution --------------------------------------------------*/ +//------------------------------------------------- +// xml_get_attribute_float_with_subst - analog +// to xml_get_attribute_float but with variable +// substitution +//------------------------------------------------- -static float xml_get_attribute_float_with_subst(running_machine &machine, xml_data_node *node, const char *attribute, float defvalue) +static float xml_get_attribute_float_with_subst(running_machine &machine, xml_data_node &node, const char *attribute, float defvalue) { const char *string = xml_get_attribute_string_with_subst(machine, node, attribute, NULL); float value; - if (!string || sscanf(string, "%f", &value) != 1) + if (string == NULL || sscanf(string, "%f", &value) != 1) return defvalue; return value; } -/*------------------------------------------------- - layout_file_load - parse a layout XML file - into a layout_file --------------------------------------------------*/ +//------------------------------------------------- +// parse_bounds - parse a bounds XML node +//------------------------------------------------- -layout_file *layout_file_load(running_machine &machine, const char *dirname, const char *filename) +void parse_bounds(running_machine &machine, xml_data_node *boundsnode, render_bounds &bounds) { - xml_data_node *rootnode, *mamelayoutnode, *elemnode, *viewnode; - layout_element **elemnext; - layout_view **viewnext; - layout_file *file; - int version; + // skip if nothing + if (boundsnode == NULL) + { + bounds.x0 = bounds.y0 = 0.0f; + bounds.x1 = bounds.y1 = 1.0f; + return; + } - /* if the first character of the "file" is an open brace, assume it is an XML string */ - if (filename[0] == '<') - rootnode = xml_string_read(filename, NULL); - - /* otherwise, assume it is a file */ + // parse out the data + if (xml_get_attribute(boundsnode, "left") != NULL) + { + // left/right/top/bottom format + bounds.x0 = xml_get_attribute_float_with_subst(machine, *boundsnode, "left", 0.0f); + bounds.x1 = xml_get_attribute_float_with_subst(machine, *boundsnode, "right", 1.0f); + bounds.y0 = xml_get_attribute_float_with_subst(machine, *boundsnode, "top", 0.0f); + bounds.y1 = xml_get_attribute_float_with_subst(machine, *boundsnode, "bottom", 1.0f); + } + else if (xml_get_attribute(boundsnode, "x") != NULL) + { + // x/y/width/height format + bounds.x0 = xml_get_attribute_float_with_subst(machine, *boundsnode, "x", 0.0f); + bounds.x1 = bounds.x0 + xml_get_attribute_float_with_subst(machine, *boundsnode, "width", 1.0f); + bounds.y0 = xml_get_attribute_float_with_subst(machine, *boundsnode, "y", 0.0f); + bounds.y1 = bounds.y0 + xml_get_attribute_float_with_subst(machine, *boundsnode, "height", 1.0f); + } else - { - file_error filerr; - mame_file *layoutfile; + throw emu_fatalerror("Illegal bounds value in XML"); - astring fname(filename, ".lay"); - if (dirname != NULL) - fname.ins(0, PATH_SEPARATOR).ins(0, dirname); - - filerr = mame_fopen(SEARCHPATH_ARTWORK, fname, OPEN_FLAG_READ, &layoutfile); - - if (filerr != FILERR_NONE) - return NULL; - rootnode = xml_file_read(mame_core_file(layoutfile), NULL); - mame_fclose(layoutfile); - } - - /* if unable to parse the file, just bail */ - if (rootnode == NULL) - return NULL; - - /* allocate the layout group object first */ - file = global_alloc_clear(layout_file); - - /* find the layout node */ - mamelayoutnode = xml_get_sibling(rootnode->child, "mamelayout"); - if (mamelayoutnode == NULL) - fatalerror("Invalid XML file: missing mamelayout node"); - - /* validate the config data version */ - version = xml_get_attribute_int(mamelayoutnode, "version", 0); - if (version != LAYOUT_VERSION) - fatalerror("Invalid XML file: unsupported version"); - - /* parse all the elements */ - file->elemlist = NULL; - elemnext = &file->elemlist; - for (elemnode = xml_get_sibling(mamelayoutnode->child, "element"); elemnode; elemnode = xml_get_sibling(elemnode->next, "element")) - { - layout_element *element = load_layout_element(machine, elemnode, dirname); - if (element == NULL) - goto error; - - /* add to the end of the list */ - *elemnext = element; - elemnext = &element->next; - } - - /* parse all the views */ - file->viewlist = NULL; - viewnext = &file->viewlist; - for (viewnode = xml_get_sibling(mamelayoutnode->child, "view"); viewnode; viewnode = xml_get_sibling(viewnode->next, "view")) - { - layout_view *view = load_layout_view(machine, viewnode, file->elemlist); - if (view == NULL) - goto error; - - /* add to the end of the list */ - *viewnext = view; - viewnext = &view->next; - } - - xml_file_free(rootnode); - return file; - -error: - layout_file_free(file); - xml_file_free(rootnode); - return NULL; + // check for errors + if (bounds.x0 > bounds.x1 || bounds.y0 > bounds.y1) + throw emu_fatalerror("Illegal bounds value in XML: (%f-%f)-(%f-%f)", bounds.x0, bounds.x1, bounds.y0, bounds.y1); } -/*------------------------------------------------- - load_layout_element - parse an element XML - node from the layout file --------------------------------------------------*/ +//------------------------------------------------- +// parse_color - parse a color XML node +//------------------------------------------------- -static layout_element *load_layout_element(running_machine &machine, xml_data_node *elemnode, const char *dirname) +void parse_color(running_machine &machine, xml_data_node *colornode, render_color &color) { - render_bounds bounds = { 0 }; - element_component **nextcomp; - element_component *component; - xml_data_node *compnode; - layout_element *element; - float xscale, yscale; - float xoffs, yoffs; - const char *name; - int state; - int first; + // skip if nothing + if (colornode == NULL) + { + color.r = color.g = color.b = color.a = 1.0f; + return; + } - /* allocate a new element */ - element = global_alloc_clear(layout_element); + // parse out the data + color.r = xml_get_attribute_float_with_subst(machine, *colornode, "red", 1.0); + color.g = xml_get_attribute_float_with_subst(machine, *colornode, "green", 1.0); + color.b = xml_get_attribute_float_with_subst(machine, *colornode, "blue", 1.0); + color.a = xml_get_attribute_float_with_subst(machine, *colornode, "alpha", 1.0); - /* extract the name */ - name = xml_get_attribute_string_with_subst(machine, elemnode, "name", NULL); + // check for errors + if (color.r < 0.0 || color.r > 1.0 || color.g < 0.0 || color.g > 1.0 || + color.b < 0.0 || color.b > 1.0 || color.a < 0.0 || color.a > 1.0) + throw emu_fatalerror("Illegal ARGB color value in XML: %f,%f,%f,%f", color.r, color.g, color.b, color.a); +} + + +//------------------------------------------------- +// parse_orientation - parse an orientation XML +// node +//------------------------------------------------- + +static void parse_orientation(running_machine &machine, xml_data_node *orientnode, int &orientation) +{ + // skip if nothing + if (orientnode == NULL) + { + orientation = ROT0; + return; + } + + // parse out the data + int rotate = xml_get_attribute_int_with_subst(machine, *orientnode, "rotate", 0); + switch (rotate) + { + case 0: orientation = ROT0; break; + case 90: orientation = ROT90; break; + case 180: orientation = ROT180; break; + case 270: orientation = ROT270; break; + default: throw emu_fatalerror("Invalid rotation in XML orientation node: %d", rotate); break; + } + if (strcmp("yes", xml_get_attribute_string_with_subst(machine, *orientnode, "swapxy", "no")) == 0) + orientation ^= ORIENTATION_SWAP_XY; + if (strcmp("yes", xml_get_attribute_string_with_subst(machine, *orientnode, "flipx", "no")) == 0) + orientation ^= ORIENTATION_FLIP_X; + if (strcmp("yes", xml_get_attribute_string_with_subst(machine, *orientnode, "flipy", "no")) == 0) + orientation ^= ORIENTATION_FLIP_Y; +} + + + +//************************************************************************** +// LAYOUT ELEMENT +//************************************************************************** + +//------------------------------------------------- +// layout_element - constructor +//------------------------------------------------- + +layout_element::layout_element(running_machine &machine, xml_data_node &elemnode, const char *dirname) + : m_next(NULL), + m_machine(machine), + m_complist(machine.m_respool), + m_defstate(0), + m_maxstate(0), + m_elemtex(NULL) +{ + // extract the name + const char *name = xml_get_attribute_string_with_subst(machine, elemnode, "name", NULL); if (name == NULL) + throw emu_fatalerror("All layout elements must have a name!\n"); + m_name = name; + + // get the default state + m_defstate = xml_get_attribute_int_with_subst(machine, elemnode, "defstate", -1); + + // parse components in order + bool first = true; + render_bounds bounds = { 0 }; + for (xml_data_node *compnode = elemnode.child; compnode != NULL; compnode = compnode->next) { - logerror("All layout elements must have a name!\n"); - goto error; - } - element->machine = &machine; - element->name = copy_string(name); - element->defstate = xml_get_attribute_int_with_subst(machine, elemnode, "defstate", -1); + // allocate a new component + component &newcomp = m_complist.append(*auto_alloc(&machine, component(machine, *compnode, dirname))); - /* parse components in order */ - first = TRUE; - nextcomp = &element->complist; - for (compnode = elemnode->child; compnode; compnode = compnode->next) - { - /* allocate a new component */ - element_component *new_component = load_element_component(machine, compnode, dirname); - if (new_component == NULL) - goto error; - - /* link it into the list */ - *nextcomp = new_component; - nextcomp = &new_component->next; - - /* accumulate bounds */ + // accumulate bounds if (first) - bounds = new_component->bounds; + bounds = newcomp.m_bounds; else - union_render_bounds(&bounds, &new_component->bounds); - first = FALSE; + union_render_bounds(&bounds, &newcomp.m_bounds); + first = false; - /* determine the maximum state */ - if (new_component->state > element->maxstate) - element->maxstate = new_component->state; - if (new_component->type == COMPONENT_TYPE_LED7SEG) - element->maxstate = 255; - if (new_component->type == COMPONENT_TYPE_LED14SEG) - element->maxstate = 16383; - if (new_component->type == COMPONENT_TYPE_LED14SEGSC || new_component->type == COMPONENT_TYPE_LED16SEG) - element->maxstate = 65535; - if (new_component->type == COMPONENT_TYPE_LED16SEGSC) - element->maxstate = 262143; - if (new_component->type == COMPONENT_TYPE_DOTMATRIX) - element->maxstate = 255; + // determine the maximum state + if (newcomp.m_state > m_maxstate) + m_maxstate = newcomp.m_state; + if (newcomp.m_type == component::CTYPE_LED7SEG) + m_maxstate = 255; + if (newcomp.m_type == component::CTYPE_LED14SEG) + m_maxstate = 16383; + if (newcomp.m_type == component::CTYPE_LED14SEGSC || newcomp.m_type == component::CTYPE_LED16SEG) + m_maxstate = 65535; + if (newcomp.m_type == component::CTYPE_LED16SEGSC) + m_maxstate = 262143; + if (newcomp.m_type == component::CTYPE_DOTMATRIX) + m_maxstate = 255; } - /* determine the scale/offset for normalization */ - xoffs = bounds.x0; - yoffs = bounds.y0; - xscale = 1.0f / (bounds.x1 - bounds.x0); - yscale = 1.0f / (bounds.y1 - bounds.y0); + + // determine the scale/offset for normalization + float xoffs = bounds.x0; + float yoffs = bounds.y0; + float xscale = 1.0f / (bounds.x1 - bounds.x0); + float yscale = 1.0f / (bounds.y1 - bounds.y0); - /* normalize all the component bounds */ - for (component = element->complist; component != NULL; component = component->next) + // normalize all the component bounds + for (component *curcomp = m_complist.first(); curcomp != NULL; curcomp = curcomp->next()) { - component->bounds.x0 = (component->bounds.x0 - xoffs) * xscale; - component->bounds.x1 = (component->bounds.x1 - xoffs) * xscale; - component->bounds.y0 = (component->bounds.y0 - yoffs) * yscale; - component->bounds.y1 = (component->bounds.y1 - yoffs) * yscale; + curcomp->m_bounds.x0 = (curcomp->m_bounds.x0 - xoffs) * xscale; + curcomp->m_bounds.x1 = (curcomp->m_bounds.x1 - xoffs) * xscale; + curcomp->m_bounds.y0 = (curcomp->m_bounds.y0 - yoffs) * yscale; + curcomp->m_bounds.y1 = (curcomp->m_bounds.y1 - yoffs) * yscale; } - /* allocate an array of element textures for the states */ - element->elemtex = global_alloc_array(element_texture, element->maxstate + 1); - for (state = 0; state <= element->maxstate; state++) - { - element->elemtex[state].element = element; - element->elemtex[state].state = state; - element->elemtex[state].texture = machine.render().texture_alloc(layout_element_scale, &element->elemtex[state]); - } - - return element; - -error: - layout_element_free(element); - return NULL; + // allocate an array of element textures for the states + m_elemtex = auto_alloc_array(&machine, texture, m_maxstate + 1); } -/*------------------------------------------------- - load_element_component - parse a component - XML node (image/rect/disk) --------------------------------------------------*/ +//------------------------------------------------- +// ~layout_element - destructor +//------------------------------------------------- -static element_component *load_element_component(running_machine &machine, xml_data_node *compnode, const char *dirname) +layout_element::~layout_element() { - element_component *component; - - /* allocate memory for the component */ - component = global_alloc_clear(element_component); - - /* fetch common data */ - component->state = xml_get_attribute_int_with_subst(machine, compnode, "state", -1); - if (load_bounds(machine, xml_get_sibling(compnode->child, "bounds"), &component->bounds)) - goto error; - if (load_color(machine, xml_get_sibling(compnode->child, "color"), &component->color)) - goto error; - - /* image nodes */ - if (strcmp(compnode->name, "image") == 0) - { - const char *file = xml_get_attribute_string_with_subst(machine, compnode, "file", NULL); - const char *afile = xml_get_attribute_string_with_subst(machine, compnode, "alphafile", NULL); - - /* load and allocate the bitmap */ - component->type = COMPONENT_TYPE_IMAGE; - component->dirname = (dirname == NULL) ? NULL : copy_string(dirname); - component->imagefile = (file == NULL) ? NULL : copy_string(file); - component->alphafile = (afile == NULL) ? NULL : copy_string(afile); - } - - /* text nodes */ - else if (strcmp(compnode->name, "text") == 0) - { - const char *text = xml_get_attribute_string_with_subst(machine, compnode, "string", ""); - char *string; - - /* allocate a copy of the string */ - component->type = COMPONENT_TYPE_TEXT; - string = global_alloc_array(char, strlen(text) + 1); - strcpy(string, text); - component->string = string; - } - - /* dotmatrix nodes */ - else if (strcmp(compnode->name, "dotmatrix") == 0) - component->type = COMPONENT_TYPE_DOTMATRIX; - - /* led7seg nodes */ - else if (strcmp(compnode->name, "led7seg") == 0) - component->type = COMPONENT_TYPE_LED7SEG; - - /* led14seg nodes */ - else if (strcmp(compnode->name, "led14seg") == 0) - component->type = COMPONENT_TYPE_LED14SEG; - - /* led14segsc nodes */ - else if (strcmp(compnode->name, "led14segsc") == 0) - component->type = COMPONENT_TYPE_LED14SEGSC; - - /* led16seg nodes */ - else if (strcmp(compnode->name, "led16seg") == 0) - component->type = COMPONENT_TYPE_LED16SEG; - - /* led16segsc nodes */ - else if (strcmp(compnode->name, "led16segsc") == 0) - component->type = COMPONENT_TYPE_LED16SEGSC; - - /* rect nodes */ - else if (strcmp(compnode->name, "rect") == 0) - component->type = COMPONENT_TYPE_RECT; - - /* disk nodes */ - else if (strcmp(compnode->name, "disk") == 0) - component->type = COMPONENT_TYPE_DISK; - - /* error otherwise */ - else - fatalerror("Unknown element component: %s", compnode->name); - - return component; - -error: - global_free(component); - return NULL; + // loop over all states and free their textures + auto_free(&m_machine, m_elemtex); } -/*------------------------------------------------- - load_layout_view - parse a view XML node --------------------------------------------------*/ +//------------------------------------------------- +// state_texture - return a pointer to a +// render_texture for the given state, allocating +// one if needed +//------------------------------------------------- -static layout_view *load_layout_view(running_machine &machine, xml_data_node *viewnode, layout_element *elemlist) +render_texture *layout_element::state_texture(int state) { - xml_data_node *boundsnode; - view_item **itemnext; - layout_view *view; - int layer; - - /* first allocate memory */ - view = global_alloc_clear(layout_view); - - /* allocate a copy of the name */ - view->name = copy_string(xml_get_attribute_string_with_subst(machine, viewnode, "name", "")); - - /* if we have a bounds item, load it */ - boundsnode = xml_get_sibling(viewnode->child, "bounds"); - if (boundsnode != NULL && load_bounds(machine, xml_get_sibling(boundsnode, "bounds"), &view->expbounds)) - goto error; - - /* loop over all the layer types we support */ - for (layer = 0; layer < ITEM_LAYER_MAX; layer++) + assert(state <= m_maxstate); + if (m_elemtex[state].m_texture == NULL) { - static const char *const layer_node_name[ITEM_LAYER_MAX] = { "backdrop", "screen", "overlay", "bezel" }; - xml_data_node *itemnode; + m_elemtex[state].m_element = this; + m_elemtex[state].m_state = state; + m_elemtex[state].m_texture = m_machine.render().texture_alloc(element_scale, &m_elemtex[state]); + } + return m_elemtex[state].m_texture; +} - /* initialize the list */ - view->itemlist[layer] = NULL; - itemnext = &view->itemlist[layer]; - /* parse all of the elements of that type */ - for (itemnode = xml_get_sibling(viewnode->child, layer_node_name[layer]); itemnode; itemnode = xml_get_sibling(itemnode->next, layer_node_name[layer])) +//------------------------------------------------- +// element_scale - scale an element by rendering +// all the components at the appropriate +// resolution +//------------------------------------------------- + +void layout_element::element_scale(bitmap_t &dest, const bitmap_t &source, const rectangle &sbounds, void *param) +{ + texture *elemtex = (texture *)param; + + // iterate over components that are part of the current state + for (component *curcomp = elemtex->m_element->m_complist.first(); curcomp != NULL; curcomp = curcomp->next()) + if (curcomp->m_state == -1 || curcomp->m_state == elemtex->m_state) { - view_item *item = load_view_item(machine, itemnode, elemlist); - if (!item) - goto error; + // get the local scaled bounds + rectangle bounds; + bounds.min_x = render_round_nearest(curcomp->bounds().x0 * dest.width); + bounds.min_y = render_round_nearest(curcomp->bounds().y0 * dest.height); + bounds.max_x = render_round_nearest(curcomp->bounds().x1 * dest.width); + bounds.max_y = render_round_nearest(curcomp->bounds().y1 * dest.height); - /* add to the end of the list */ - *itemnext = item; - itemnext = &item->next; + // based on the component type, add to the texture + curcomp->draw(elemtex->m_element->m_machine, dest, bounds, elemtex->m_state); + } +} + + +//************************************************************************** +// LAYOUT ELEMENT TEXTURE +//************************************************************************** + +//------------------------------------------------- +// texture - constructor +//------------------------------------------------- + +layout_element::texture::texture() + : m_element(NULL), + m_texture(NULL), + m_state(0) +{ +} + + +//------------------------------------------------- +// ~texture - destructor +//------------------------------------------------- + +layout_element::texture::~texture() +{ + if (m_element != NULL) + m_element->m_machine.render().texture_free(m_texture); +} + + + +//************************************************************************** +// LAYOUT ELEMENT COMPONENT +//************************************************************************** + +//------------------------------------------------- +// component - constructor +//------------------------------------------------- + +layout_element::component::component(running_machine &machine, xml_data_node &compnode, const char *dirname) + : m_next(NULL), + m_type(CTYPE_INVALID), + m_state(0), + m_bitmap(NULL), + m_hasalpha(false) +{ + // fetch common data + m_state = xml_get_attribute_int_with_subst(machine, compnode, "state", -1); + parse_bounds(machine, xml_get_sibling(compnode.child, "bounds"), m_bounds); + parse_color(machine, xml_get_sibling(compnode.child, "color"), m_color); + + // image nodes + if (strcmp(compnode.name, "image") == 0) + { + m_type = CTYPE_IMAGE; + m_dirname = dirname; + m_imagefile = xml_get_attribute_string_with_subst(machine, compnode, "file", ""); + m_alphafile = xml_get_attribute_string_with_subst(machine, compnode, "alphafile", ""); + } + + // text nodes + else if (strcmp(compnode.name, "text") == 0) + { + m_type = CTYPE_TEXT; + m_string = xml_get_attribute_string_with_subst(machine, compnode, "string", ""); + } + + // dotmatrix nodes + else if (strcmp(compnode.name, "dotmatrix") == 0) + m_type = CTYPE_DOTMATRIX; + + // led7seg nodes + else if (strcmp(compnode.name, "led7seg") == 0) + m_type = CTYPE_LED7SEG; + + // led14seg nodes + else if (strcmp(compnode.name, "led14seg") == 0) + m_type = CTYPE_LED14SEG; + + // led14segsc nodes + else if (strcmp(compnode.name, "led14segsc") == 0) + m_type = CTYPE_LED14SEGSC; + + // led16seg nodes + else if (strcmp(compnode.name, "led16seg") == 0) + m_type = CTYPE_LED16SEG; + + // led16segsc nodes + else if (strcmp(compnode.name, "led16segsc") == 0) + m_type = CTYPE_LED16SEGSC; + + // rect nodes + else if (strcmp(compnode.name, "rect") == 0) + m_type = CTYPE_RECT; + + // disk nodes + else if (strcmp(compnode.name, "disk") == 0) + m_type = CTYPE_DISK; + + // error otherwise + else + throw emu_fatalerror("Unknown element component: %s", compnode.name); +} + + +//------------------------------------------------- +// ~component - destructor +//------------------------------------------------- + +layout_element::component::~component() +{ + global_free(m_bitmap); +} + + +//------------------------------------------------- +// draw - draw a component +//------------------------------------------------- + +void layout_element::component::draw(running_machine &machine, bitmap_t &dest, const rectangle &bounds, int state) +{ + switch (m_type) + { + case CTYPE_IMAGE: + if (m_bitmap == NULL) + m_bitmap = load_bitmap(); + render_resample_argb_bitmap_hq( + BITMAP_ADDR32(&dest, bounds.min_y, bounds.min_x), + dest.rowpixels, + bounds.max_x - bounds.min_x, + bounds.max_y - bounds.min_y, + m_bitmap, NULL, &m_color); + break; + + case CTYPE_RECT: + draw_rect(dest, bounds); + break; + + case CTYPE_DISK: + draw_disk(dest, bounds); + break; + + case CTYPE_TEXT: + draw_text(machine, dest, bounds); + break; + + case CTYPE_LED7SEG: + draw_led7seg(dest, bounds, state); + break; + + case CTYPE_LED14SEG: + draw_led14seg(dest, bounds, state); + break; + + case CTYPE_LED16SEG: + draw_led16seg(dest, bounds, state); + break; + + case CTYPE_LED14SEGSC: + draw_led14segsc(dest, bounds, state); + break; + + case CTYPE_LED16SEGSC: + draw_led16segsc(dest, bounds, state); + break; + + case CTYPE_DOTMATRIX: + draw_dotmatrix(dest, bounds, state); + break; + + default: + throw emu_fatalerror("Unknown component type requested draw()"); + } +} + + +//------------------------------------------------- +// draw_rect - draw a rectangle in the specified +// color +//------------------------------------------------- + +void layout_element::component::draw_rect(bitmap_t &dest, const rectangle &bounds) +{ + // compute premultiplied colors + UINT32 r = m_color.r * m_color.a * 255.0; + UINT32 g = m_color.g * m_color.a * 255.0; + UINT32 b = m_color.b * m_color.a * 255.0; + UINT32 inva = (1.0f - m_color.a) * 255.0; + + // iterate over X and Y + for (UINT32 y = bounds.min_y; y < bounds.max_y; y++) + for (UINT32 x = bounds.min_x; x < bounds.max_x; x++) + { + UINT32 finalr = r; + UINT32 finalg = g; + UINT32 finalb = b; + + // if we're translucent, add in the destination pixel contribution + if (inva > 0) + { + UINT32 dpix = *BITMAP_ADDR32(&dest, y, x); + finalr += (RGB_RED(dpix) * inva) >> 8; + finalg += (RGB_GREEN(dpix) * inva) >> 8; + finalb += (RGB_BLUE(dpix) * inva) >> 8; + } + + // store the target pixel, dividing the RGBA values by the overall scale factor + *BITMAP_ADDR32(&dest, y, x) = MAKE_ARGB(0xff, finalr, finalg, finalb); + } +} + + +//------------------------------------------------- +// draw_disk - draw an ellipse in the specified +// color +//------------------------------------------------- + +void layout_element::component::draw_disk(bitmap_t &dest, const rectangle &bounds) +{ + // compute premultiplied colors + UINT32 r = m_color.r * m_color.a * 255.0; + UINT32 g = m_color.g * m_color.a * 255.0; + UINT32 b = m_color.b * m_color.a * 255.0; + UINT32 inva = (1.0f - m_color.a) * 255.0; + + // find the center + float xcenter = (float)(bounds.min_x + bounds.max_x) * 0.5f; + float ycenter = (float)(bounds.min_y + bounds.max_y) * 0.5f; + float xradius = (float)(bounds.max_x - bounds.min_x) * 0.5f; + float yradius = (float)(bounds.max_y - bounds.min_y) * 0.5f; + float ooyradius2 = 1.0f / (yradius * yradius); + + // iterate over y + for (UINT32 y = bounds.min_y; y < bounds.max_y; y++) + { + float ycoord = ycenter - ((float)y + 0.5f); + float xval = xradius * sqrt(1.0f - (ycoord * ycoord) * ooyradius2); + + // compute left/right coordinates + INT32 left = (INT32)(xcenter - xval + 0.5f); + INT32 right = (INT32)(xcenter + xval + 0.5f); + + // draw this scanline + for (UINT32 x = left; x < right; x++) + { + UINT32 finalr = r; + UINT32 finalg = g; + UINT32 finalb = b; + + // if we're translucent, add in the destination pixel contribution + if (inva > 0) + { + UINT32 dpix = *BITMAP_ADDR32(&dest, y, x); + finalr += (RGB_RED(dpix) * inva) >> 8; + finalg += (RGB_GREEN(dpix) * inva) >> 8; + finalb += (RGB_BLUE(dpix) * inva) >> 8; + } + + // store the target pixel, dividing the RGBA values by the overall scale factor + *BITMAP_ADDR32(&dest, y, x) = MAKE_ARGB(0xff, finalr, finalg, finalb); } } - - /* recompute the data for the view */ - layout_view_recompute(view, ~0); - return view; - -error: - layout_view_free(view); - return NULL; } -/*------------------------------------------------- - load_view_item - parse an item XML node --------------------------------------------------*/ +//------------------------------------------------- +// draw_text - draw text in the specified color +//------------------------------------------------- -static view_item *load_view_item(running_machine &machine, xml_data_node *itemnode, layout_element *elemlist) +void layout_element::component::draw_text(running_machine &machine, bitmap_t &dest, const rectangle &bounds) { - view_item *item; - const char *name; + // compute premultiplied colors + UINT32 r = m_color.r * 255.0; + UINT32 g = m_color.g * 255.0; + UINT32 b = m_color.b * 255.0; + UINT32 a = m_color.a * 255.0; - /* allocate a new item */ - item = global_alloc_clear(view_item); - - /* allocate a copy of the output name */ - item->output_name = copy_string(xml_get_attribute_string_with_subst(machine, itemnode, "name", "")); - - /* allocate a copy of the input tag */ - item->input_tag = copy_string(xml_get_attribute_string_with_subst(machine, itemnode, "inputtag", "")); - - /* find the associated element */ - name = xml_get_attribute_string_with_subst(machine, itemnode, "element", NULL); - if (name != NULL) + // get the width of the string + render_font *font = render_font_alloc(machine, NULL); + float aspect = 1.0f; + INT32 width; + while (1) { - layout_element *element; + width = render_font_get_string_width(font, bounds.max_y - bounds.min_y, aspect, m_string); + if (width < bounds.max_x - bounds.min_x) + break; + aspect *= 0.9f; + } + INT32 curx = bounds.min_x + (bounds.max_x - bounds.min_x - width) / 2; - /* search the list of elements for a match */ - for (element = elemlist; element; element = element->next) - if (strcmp(name, element->name) == 0) - break; + // allocate a temporary bitmap + bitmap_t *tempbitmap = global_alloc(bitmap_t(dest.width, dest.height, BITMAP_FORMAT_ARGB32)); - /* error if not found */ - if (element == NULL) - fatalerror("Unable to find layout element %s", name); - item->element = element; + // loop over characters + for (const char *s = m_string; *s != 0; s++) + { + // get the font bitmap + rectangle chbounds; + render_font_get_scaled_bitmap_and_bounds(font, tempbitmap, bounds.max_y - bounds.min_y, aspect, *s, &chbounds); + + // copy the data into the target + for (int y = 0; y < chbounds.max_y - chbounds.min_y; y++) + { + int effy = bounds.min_y + y; + if (effy >= bounds.min_y && effy <= bounds.max_y) + { + UINT32 *src = BITMAP_ADDR32(tempbitmap, y, 0); + UINT32 *d = BITMAP_ADDR32(&dest, effy, 0); + for (int x = 0; x < chbounds.max_x - chbounds.min_x; x++) + { + int effx = curx + x + chbounds.min_x; + if (effx >= bounds.min_x && effx <= bounds.max_x) + { + UINT32 spix = RGB_ALPHA(src[x]); + if (spix != 0) + { + UINT32 dpix = d[effx]; + UINT32 ta = (a * (spix + 1)) >> 8; + UINT32 tr = (r * ta + RGB_RED(dpix) * (0x100 - ta)) >> 8; + UINT32 tg = (g * ta + RGB_GREEN(dpix) * (0x100 - ta)) >> 8; + UINT32 tb = (b * ta + RGB_BLUE(dpix) * (0x100 - ta)) >> 8; + d[effx] = MAKE_ARGB(0xff, tr, tg, tb); + } + } + } + } + } + + // advance in the X direction + curx += render_font_get_char_width(font, bounds.max_y - bounds.min_y, aspect, *s); } - /* fetch common data */ - item->index = xml_get_attribute_int_with_subst(machine, itemnode, "index", -1); - item->input_mask = xml_get_attribute_int_with_subst(machine, itemnode, "inputmask", 0); - if (item->output_name[0] != 0 && item->element != 0) - output_set_value(item->output_name, item->element->defstate); - if (load_bounds(machine, xml_get_sibling(itemnode->child, "bounds"), &item->rawbounds)) - goto error; - if (load_color(machine, xml_get_sibling(itemnode->child, "color"), &item->color)) - goto error; - if (load_orientation(machine, xml_get_sibling(itemnode->child, "orientation"), &item->orientation)) - goto error; - - /* sanity checks */ - if (strcmp(itemnode->name, "screen") == 0) - { - if (item->index < 0) - fatalerror("Layout references invalid screen index %d", item->index); - } - else - { - if (item->element == NULL) - fatalerror("Layout item of type %s require an element tag", itemnode->name); - } - - return item; - -error: - if (item->output_name != NULL) - global_free(item->output_name); - if (item->input_tag != NULL) - global_free(item->input_tag); - global_free(item); - return NULL; + // free the temporary bitmap and font + global_free(tempbitmap); + render_font_free(font); } -/*------------------------------------------------- - load_component_bitmap - load a PNG file - with artwork for a component --------------------------------------------------*/ +//------------------------------------------------- +// load_bitmap - load a PNG file with artwork for +// a component +//------------------------------------------------- -static bitmap_t *load_component_bitmap(const char *dirname, const char *file, const char *alphafile, int *hasalpha) +bitmap_t *layout_element::component::load_bitmap() { - bitmap_t *bitmap; + // load the basic bitmap + bitmap_t *bitmap = render_load_png(OPTION_ARTPATH, m_dirname, m_imagefile, NULL, &m_hasalpha); + if (bitmap != NULL && m_alphafile) - /* load the basic bitmap */ - bitmap = render_load_png(OPTION_ARTPATH, dirname, file, NULL, hasalpha); - if (bitmap != NULL && alphafile != NULL) - - /* load the alpha bitmap if specified */ - if (render_load_png(OPTION_ARTPATH, dirname, alphafile, bitmap, hasalpha) == NULL) + // load the alpha bitmap if specified + if (render_load_png(OPTION_ARTPATH, m_dirname, m_alphafile, bitmap, &m_hasalpha) == NULL) { global_free(bitmap); bitmap = NULL; } - /* if we can't load the bitmap, allocate a dummy one and report an error */ + // if we can't load the bitmap, allocate a dummy one and report an error if (bitmap == NULL) { - int step, line; - - /* draw some stripes in the bitmap */ + // draw some stripes in the bitmap bitmap = global_alloc(bitmap_t(100, 100, BITMAP_FORMAT_ARGB32)); bitmap_fill(bitmap, NULL, 0); - for (step = 0; step < 100; step += 25) - for (line = 0; line < 100; line++) + for (int step = 0; step < 100; step += 25) + for (int line = 0; line < 100; line++) *BITMAP_ADDR32(bitmap, (step + line) % 100, line % 100) = MAKE_ARGB(0xff,0xff,0xff,0xff); - /* log an error */ - if (alphafile == NULL) - logerror("Unable to load component bitmap '%s'", file); + // log an error + if (!m_alphafile) + mame_printf_warning("Unable to load component bitmap '%s'", m_imagefile.cstr()); else - logerror("Unable to load component bitmap '%s'/'%s'", file, alphafile); + mame_printf_warning("Unable to load component bitmap '%s'/'%s'", m_imagefile.cstr(), m_alphafile.cstr()); } return bitmap; } -/*------------------------------------------------- - load_bounds - parse a bounds XML node --------------------------------------------------*/ +//------------------------------------------------- +// draw_led7seg - draw a 7-segment LCD +//------------------------------------------------- -static int load_bounds(running_machine &machine, xml_data_node *boundsnode, render_bounds *bounds) +void layout_element::component::draw_led7seg(bitmap_t &dest, const rectangle &bounds, int pattern) { - /* skip if nothing */ - if (boundsnode == NULL) + const rgb_t onpen = MAKE_ARGB(0xff,0xff,0xff,0xff); + const rgb_t offpen = MAKE_ARGB(0xff,0x20,0x20,0x20); + + // sizes for computation + int bmwidth = 250; + int bmheight = 400; + int segwidth = 40; + int skewwidth = 40; + + // allocate a temporary bitmap for drawing + bitmap_t *tempbitmap = global_alloc(bitmap_t(bmwidth + skewwidth, bmheight, BITMAP_FORMAT_ARGB32)); + bitmap_fill(tempbitmap, NULL, MAKE_ARGB(0xff,0x00,0x00,0x00)); + + // top bar + draw_segment_horizontal(*tempbitmap, 0 + 2*segwidth/3, bmwidth - 2*segwidth/3, 0 + segwidth/2, segwidth, (pattern & (1 << 0)) ? onpen : offpen); + + // top-right bar + draw_segment_vertical(*tempbitmap, 0 + 2*segwidth/3, bmheight/2 - segwidth/3, bmwidth - segwidth/2, segwidth, (pattern & (1 << 1)) ? onpen : offpen); + + // bottom-right bar + draw_segment_vertical(*tempbitmap, bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, bmwidth - segwidth/2, segwidth, (pattern & (1 << 2)) ? onpen : offpen); + + // bottom bar + draw_segment_horizontal(*tempbitmap, 0 + 2*segwidth/3, bmwidth - 2*segwidth/3, bmheight - segwidth/2, segwidth, (pattern & (1 << 3)) ? onpen : offpen); + + // bottom-left bar + draw_segment_vertical(*tempbitmap, bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, 0 + segwidth/2, segwidth, (pattern & (1 << 4)) ? onpen : offpen); + + // top-left bar + draw_segment_vertical(*tempbitmap, 0 + 2*segwidth/3, bmheight/2 - segwidth/3, 0 + segwidth/2, segwidth, (pattern & (1 << 5)) ? onpen : offpen); + + // middle bar + draw_segment_horizontal(*tempbitmap, 0 + 2*segwidth/3, bmwidth - 2*segwidth/3, bmheight/2, segwidth, (pattern & (1 << 6)) ? onpen : offpen); + + // apply skew + apply_skew(*tempbitmap, 40); + + // decimal point + draw_segment_decimal(*tempbitmap, bmwidth + segwidth/2, bmheight - segwidth/2, segwidth, (pattern & (1 << 7)) ? onpen : offpen); + + // resample to the target size + render_resample_argb_bitmap_hq(dest.base, dest.rowpixels, dest.width, dest.height, tempbitmap, NULL, &m_color); + + global_free(tempbitmap); +} + + +//------------------------------------------------- +// draw_led14seg - draw a 14-segment LCD +//------------------------------------------------- + +void layout_element::component::draw_led14seg(bitmap_t &dest, const rectangle &bounds, int pattern) +{ + const rgb_t onpen = MAKE_ARGB(0xff, 0xff, 0xff, 0xff); + const rgb_t offpen = MAKE_ARGB(0xff, 0x20, 0x20, 0x20); + + // sizes for computation + int bmwidth = 250; + int bmheight = 400; + int segwidth = 40; + int skewwidth = 40; + + // allocate a temporary bitmap for drawing + bitmap_t *tempbitmap = global_alloc(bitmap_t(bmwidth + skewwidth, bmheight, BITMAP_FORMAT_ARGB32)); + bitmap_fill(tempbitmap, NULL, MAKE_ARGB(0xff, 0x00, 0x00, 0x00)); + + // top bar + draw_segment_horizontal(*tempbitmap, + 0 + 2*segwidth/3, bmwidth - 2*segwidth/3, 0 + segwidth/2, + segwidth, (pattern & (1 << 0)) ? onpen : offpen); + + // right-top bar + draw_segment_vertical(*tempbitmap, + 0 + 2*segwidth/3, bmheight/2 - segwidth/3, bmwidth - segwidth/2, + segwidth, (pattern & (1 << 1)) ? onpen : offpen); + + // right-bottom bar + draw_segment_vertical(*tempbitmap, + bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, bmwidth - segwidth/2, + segwidth, (pattern & (1 << 2)) ? onpen : offpen); + + // bottom bar + draw_segment_horizontal(*tempbitmap, + 0 + 2*segwidth/3, bmwidth - 2*segwidth/3, bmheight - segwidth/2, + segwidth, (pattern & (1 << 3)) ? onpen : offpen); + + // left-bottom bar + draw_segment_vertical(*tempbitmap, + bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, 0 + segwidth/2, + segwidth, (pattern & (1 << 4)) ? onpen : offpen); + + // left-top bar + draw_segment_vertical(*tempbitmap, + 0 + 2*segwidth/3, bmheight/2 - segwidth/3, 0 + segwidth/2, + segwidth, (pattern & (1 << 5)) ? onpen : offpen); + + // horizontal-middle-left bar + draw_segment_horizontal_caps(*tempbitmap, + 0 + 2*segwidth/3, bmwidth/2 - segwidth/10, bmheight/2, + segwidth, LINE_CAP_START, (pattern & (1 << 6)) ? onpen : offpen); + + // horizontal-middle-right bar + draw_segment_horizontal_caps(*tempbitmap, + 0 + bmwidth/2 + segwidth/10, bmwidth - 2*segwidth/3, bmheight/2, + segwidth, LINE_CAP_END, (pattern & (1 << 7)) ? onpen : offpen); + + // vertical-middle-top bar + draw_segment_vertical_caps(*tempbitmap, + 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3, bmwidth/2, + segwidth, LINE_CAP_NONE, (pattern & (1 << 8)) ? onpen : offpen); + + // vertical-middle-bottom bar + draw_segment_vertical_caps(*tempbitmap, + bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3, bmwidth/2, + segwidth, LINE_CAP_NONE, (pattern & (1 << 9)) ? onpen : offpen); + + // diagonal-left-bottom bar + draw_segment_diagonal_1(*tempbitmap, + 0 + segwidth + segwidth/5, bmwidth/2 - segwidth/2 - segwidth/5, + bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3, + segwidth, (pattern & (1 << 10)) ? onpen : offpen); + + // diagonal-left-top bar + draw_segment_diagonal_2(*tempbitmap, + 0 + segwidth + segwidth/5, bmwidth/2 - segwidth/2 - segwidth/5, + 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3, + segwidth, (pattern & (1 << 11)) ? onpen : offpen); + + // diagonal-right-top bar + draw_segment_diagonal_1(*tempbitmap, + bmwidth/2 + segwidth/2 + segwidth/5, bmwidth - segwidth - segwidth/5, + 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3, + segwidth, (pattern & (1 << 12)) ? onpen : offpen); + + // diagonal-right-bottom bar + draw_segment_diagonal_2(*tempbitmap, + bmwidth/2 + segwidth/2 + segwidth/5, bmwidth - segwidth - segwidth/5, + bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3, + segwidth, (pattern & (1 << 13)) ? onpen : offpen); + + // apply skew + apply_skew(*tempbitmap, 40); + + // resample to the target size + render_resample_argb_bitmap_hq(dest.base, dest.rowpixels, dest.width, dest.height, tempbitmap, NULL, &m_color); + + global_free(tempbitmap); +} + + +//------------------------------------------------- +// draw_led14segsc - draw a 14-segment LCD with +// semicolon (2 extra segments) +//------------------------------------------------- + +void layout_element::component::draw_led14segsc(bitmap_t &dest, const rectangle &bounds, int pattern) +{ + const rgb_t onpen = MAKE_ARGB(0xff, 0xff, 0xff, 0xff); + const rgb_t offpen = MAKE_ARGB(0xff, 0x20, 0x20, 0x20); + + // sizes for computation + int bmwidth = 250; + int bmheight = 400; + int segwidth = 40; + int skewwidth = 40; + + // allocate a temporary bitmap for drawing, adding some extra space for the tail + bitmap_t *tempbitmap = global_alloc(bitmap_t(bmwidth + skewwidth, bmheight + segwidth, BITMAP_FORMAT_ARGB32)); + bitmap_fill(tempbitmap, NULL, MAKE_ARGB(0xff, 0x00, 0x00, 0x00)); + + // top bar + draw_segment_horizontal(*tempbitmap, + 0 + 2*segwidth/3, bmwidth - 2*segwidth/3, 0 + segwidth/2, + segwidth, (pattern & (1 << 0)) ? onpen : offpen); + + // right-top bar + draw_segment_vertical(*tempbitmap, + 0 + 2*segwidth/3, bmheight/2 - segwidth/3, bmwidth - segwidth/2, + segwidth, (pattern & (1 << 1)) ? onpen : offpen); + + // right-bottom bar + draw_segment_vertical(*tempbitmap, + bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, bmwidth - segwidth/2, + segwidth, (pattern & (1 << 2)) ? onpen : offpen); + + // bottom bar + draw_segment_horizontal(*tempbitmap, + 0 + 2*segwidth/3, bmwidth - 2*segwidth/3, bmheight - segwidth/2, + segwidth, (pattern & (1 << 3)) ? onpen : offpen); + + // left-bottom bar + draw_segment_vertical(*tempbitmap, + bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, 0 + segwidth/2, + segwidth, (pattern & (1 << 4)) ? onpen : offpen); + + // left-top bar + draw_segment_vertical(*tempbitmap, + 0 + 2*segwidth/3, bmheight/2 - segwidth/3, 0 + segwidth/2, + segwidth, (pattern & (1 << 5)) ? onpen : offpen); + + // horizontal-middle-left bar + draw_segment_horizontal_caps(*tempbitmap, + 0 + 2*segwidth/3, bmwidth/2 - segwidth/10, bmheight/2, + segwidth, LINE_CAP_START, (pattern & (1 << 6)) ? onpen : offpen); + + // horizontal-middle-right bar + draw_segment_horizontal_caps(*tempbitmap, + 0 + bmwidth/2 + segwidth/10, bmwidth - 2*segwidth/3, bmheight/2, + segwidth, LINE_CAP_END, (pattern & (1 << 7)) ? onpen : offpen); + + // vertical-middle-top bar + draw_segment_vertical_caps(*tempbitmap, + 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3, bmwidth/2, + segwidth, LINE_CAP_NONE, (pattern & (1 << 8)) ? onpen : offpen); + + // vertical-middle-bottom bar + draw_segment_vertical_caps(*tempbitmap, + bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3, bmwidth/2, + segwidth, LINE_CAP_NONE, (pattern & (1 << 9)) ? onpen : offpen); + + // diagonal-left-bottom bar + draw_segment_diagonal_1(*tempbitmap, + 0 + segwidth + segwidth/5, bmwidth/2 - segwidth/2 - segwidth/5, + bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3, + segwidth, (pattern & (1 << 10)) ? onpen : offpen); + + // diagonal-left-top bar + draw_segment_diagonal_2(*tempbitmap, + 0 + segwidth + segwidth/5, bmwidth/2 - segwidth/2 - segwidth/5, + 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3, + segwidth, (pattern & (1 << 11)) ? onpen : offpen); + + // diagonal-right-top bar + draw_segment_diagonal_1(*tempbitmap, + bmwidth/2 + segwidth/2 + segwidth/5, bmwidth - segwidth - segwidth/5, + 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3, + segwidth, (pattern & (1 << 12)) ? onpen : offpen); + + // diagonal-right-bottom bar + draw_segment_diagonal_2(*tempbitmap, + bmwidth/2 + segwidth/2 + segwidth/5, bmwidth - segwidth - segwidth/5, + bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3, + segwidth, (pattern & (1 << 13)) ? onpen : offpen); + + // apply skew + apply_skew(*tempbitmap, 40); + + // decimal point + draw_segment_decimal(*tempbitmap, bmwidth + segwidth/2, bmheight - segwidth/2, segwidth, (pattern & (1 << 14)) ? onpen : offpen); + + // comma tail + draw_segment_diagonal_1(*tempbitmap, + bmwidth - (segwidth/2), bmwidth + segwidth, + bmheight - (segwidth), bmheight + segwidth*1.5, + segwidth/2, (pattern & (1 << 15)) ? onpen : offpen); + + // resample to the target size + render_resample_argb_bitmap_hq(dest.base, dest.rowpixels, dest.width, dest.height, tempbitmap, NULL, &m_color); + + global_free(tempbitmap); +} + + +//------------------------------------------------- +// draw_led16seg - draw a 16-segment LCD +//------------------------------------------------- + +void layout_element::component::draw_led16seg(bitmap_t &dest, const rectangle &bounds, int pattern) +{ + const rgb_t onpen = MAKE_ARGB(0xff, 0xff, 0xff, 0xff); + const rgb_t offpen = MAKE_ARGB(0xff, 0x20, 0x20, 0x20); + + // sizes for computation + int bmwidth = 250; + int bmheight = 400; + int segwidth = 40; + int skewwidth = 40; + + // allocate a temporary bitmap for drawing + bitmap_t *tempbitmap = global_alloc(bitmap_t(bmwidth + skewwidth, bmheight, BITMAP_FORMAT_ARGB32)); + bitmap_fill(tempbitmap, NULL, MAKE_ARGB(0xff, 0x00, 0x00, 0x00)); + + // top-left bar + draw_segment_horizontal_caps(*tempbitmap, + 0 + 2*segwidth/3, bmwidth/2 - segwidth/10, 0 + segwidth/2, + segwidth, LINE_CAP_START, (pattern & (1 << 0)) ? onpen : offpen); + + // top-right bar + draw_segment_horizontal_caps(*tempbitmap, + 0 + bmwidth/2 + segwidth/10, bmwidth - 2*segwidth/3, 0 + segwidth/2, + segwidth, LINE_CAP_END, (pattern & (1 << 1)) ? onpen : offpen); + + // right-top bar + draw_segment_vertical(*tempbitmap, + 0 + 2*segwidth/3, bmheight/2 - segwidth/3, bmwidth - segwidth/2, + segwidth, (pattern & (1 << 2)) ? onpen : offpen); + + // right-bottom bar + draw_segment_vertical(*tempbitmap, + bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, bmwidth - segwidth/2, + segwidth, (pattern & (1 << 3)) ? onpen : offpen); + + // bottom-right bar + draw_segment_horizontal_caps(*tempbitmap, + 0 + bmwidth/2 + segwidth/10, bmwidth - 2*segwidth/3, bmheight - segwidth/2, + segwidth, LINE_CAP_END, (pattern & (1 << 4)) ? onpen : offpen); + + // bottom-left bar + draw_segment_horizontal_caps(*tempbitmap, + 0 + 2*segwidth/3, bmwidth/2 - segwidth/10, bmheight - segwidth/2, + segwidth, LINE_CAP_START, (pattern & (1 << 5)) ? onpen : offpen); + + // left-bottom bar + draw_segment_vertical(*tempbitmap, + bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, 0 + segwidth/2, + segwidth, (pattern & (1 << 6)) ? onpen : offpen); + + // left-top bar + draw_segment_vertical(*tempbitmap, + 0 + 2*segwidth/3, bmheight/2 - segwidth/3, 0 + segwidth/2, + segwidth, (pattern & (1 << 7)) ? onpen : offpen); + + // horizontal-middle-left bar + draw_segment_horizontal_caps(*tempbitmap, + 0 + 2*segwidth/3, bmwidth/2 - segwidth/10, bmheight/2, + segwidth, LINE_CAP_START, (pattern & (1 << 8)) ? onpen : offpen); + + // horizontal-middle-right bar + draw_segment_horizontal_caps(*tempbitmap, + 0 + bmwidth/2 + segwidth/10, bmwidth - 2*segwidth/3, bmheight/2, + segwidth, LINE_CAP_END, (pattern & (1 << 9)) ? onpen : offpen); + + // vertical-middle-top bar + draw_segment_vertical_caps(*tempbitmap, + 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3, bmwidth/2, + segwidth, LINE_CAP_NONE, (pattern & (1 << 10)) ? onpen : offpen); + + // vertical-middle-bottom bar + draw_segment_vertical_caps(*tempbitmap, + bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3, bmwidth/2, + segwidth, LINE_CAP_NONE, (pattern & (1 << 11)) ? onpen : offpen); + + // diagonal-left-bottom bar + draw_segment_diagonal_1(*tempbitmap, + 0 + segwidth + segwidth/5, bmwidth/2 - segwidth/2 - segwidth/5, + bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3, + segwidth, (pattern & (1 << 12)) ? onpen : offpen); + + // diagonal-left-top bar + draw_segment_diagonal_2(*tempbitmap, + 0 + segwidth + segwidth/5, bmwidth/2 - segwidth/2 - segwidth/5, + 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3, + segwidth, (pattern & (1 << 13)) ? onpen : offpen); + + // diagonal-right-top bar + draw_segment_diagonal_1(*tempbitmap, + bmwidth/2 + segwidth/2 + segwidth/5, bmwidth - segwidth - segwidth/5, + 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3, + segwidth, (pattern & (1 << 14)) ? onpen : offpen); + + // diagonal-right-bottom bar + draw_segment_diagonal_2(*tempbitmap, + bmwidth/2 + segwidth/2 + segwidth/5, bmwidth - segwidth - segwidth/5, + bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3, + segwidth, (pattern & (1 << 15)) ? onpen : offpen); + + // apply skew + apply_skew(*tempbitmap, 40); + + // resample to the target size + render_resample_argb_bitmap_hq(dest.base, dest.rowpixels, dest.width, dest.height, tempbitmap, NULL, &m_color); + + global_free(tempbitmap); +} + + +//------------------------------------------------- +// draw_led16segsc - draw a 16-segment LCD with +// semicolon (2 extra segments) +//------------------------------------------------- + +void layout_element::component::draw_led16segsc(bitmap_t &dest, const rectangle &bounds, int pattern) +{ + const rgb_t onpen = MAKE_ARGB(0xff, 0xff, 0xff, 0xff); + const rgb_t offpen = MAKE_ARGB(0xff, 0x20, 0x20, 0x20); + + // sizes for computation + int bmwidth = 250; + int bmheight = 400; + int segwidth = 40; + int skewwidth = 40; + + // allocate a temporary bitmap for drawing + bitmap_t *tempbitmap = global_alloc(bitmap_t(bmwidth + skewwidth, bmheight + segwidth, BITMAP_FORMAT_ARGB32)); + bitmap_fill(tempbitmap, NULL, MAKE_ARGB(0xff, 0x00, 0x00, 0x00)); + + // top-left bar + draw_segment_horizontal_caps(*tempbitmap, + 0 + 2*segwidth/3, bmwidth/2 - segwidth/10, 0 + segwidth/2, + segwidth, LINE_CAP_START, (pattern & (1 << 0)) ? onpen : offpen); + + // top-right bar + draw_segment_horizontal_caps(*tempbitmap, + 0 + bmwidth/2 + segwidth/10, bmwidth - 2*segwidth/3, 0 + segwidth/2, + segwidth, LINE_CAP_END, (pattern & (1 << 1)) ? onpen : offpen); + + // right-top bar + draw_segment_vertical(*tempbitmap, + 0 + 2*segwidth/3, bmheight/2 - segwidth/3, bmwidth - segwidth/2, + segwidth, (pattern & (1 << 2)) ? onpen : offpen); + + // right-bottom bar + draw_segment_vertical(*tempbitmap, + bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, bmwidth - segwidth/2, + segwidth, (pattern & (1 << 3)) ? onpen : offpen); + + // bottom-right bar + draw_segment_horizontal_caps(*tempbitmap, + 0 + bmwidth/2 + segwidth/10, bmwidth - 2*segwidth/3, bmheight - segwidth/2, + segwidth, LINE_CAP_END, (pattern & (1 << 4)) ? onpen : offpen); + + // bottom-left bar + draw_segment_horizontal_caps(*tempbitmap, + 0 + 2*segwidth/3, bmwidth/2 - segwidth/10, bmheight - segwidth/2, + segwidth, LINE_CAP_START, (pattern & (1 << 5)) ? onpen : offpen); + + // left-bottom bar + draw_segment_vertical(*tempbitmap, + bmheight/2 + segwidth/3, bmheight - 2*segwidth/3, 0 + segwidth/2, + segwidth, (pattern & (1 << 6)) ? onpen : offpen); + + // left-top bar + draw_segment_vertical(*tempbitmap, + 0 + 2*segwidth/3, bmheight/2 - segwidth/3, 0 + segwidth/2, + segwidth, (pattern & (1 << 7)) ? onpen : offpen); + + // horizontal-middle-left bar + draw_segment_horizontal_caps(*tempbitmap, + 0 + 2*segwidth/3, bmwidth/2 - segwidth/10, bmheight/2, + segwidth, LINE_CAP_START, (pattern & (1 << 8)) ? onpen : offpen); + + // horizontal-middle-right bar + draw_segment_horizontal_caps(*tempbitmap, + 0 + bmwidth/2 + segwidth/10, bmwidth - 2*segwidth/3, bmheight/2, + segwidth, LINE_CAP_END, (pattern & (1 << 9)) ? onpen : offpen); + + // vertical-middle-top bar + draw_segment_vertical_caps(*tempbitmap, + 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3, bmwidth/2, + segwidth, LINE_CAP_NONE, (pattern & (1 << 10)) ? onpen : offpen); + + // vertical-middle-bottom bar + draw_segment_vertical_caps(*tempbitmap, + bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3, bmwidth/2, + segwidth, LINE_CAP_NONE, (pattern & (1 << 11)) ? onpen : offpen); + + // diagonal-left-bottom bar + draw_segment_diagonal_1(*tempbitmap, + 0 + segwidth + segwidth/5, bmwidth/2 - segwidth/2 - segwidth/5, + bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3, + segwidth, (pattern & (1 << 12)) ? onpen : offpen); + + // diagonal-left-top bar + draw_segment_diagonal_2(*tempbitmap, + 0 + segwidth + segwidth/5, bmwidth/2 - segwidth/2 - segwidth/5, + 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3, + segwidth, (pattern & (1 << 13)) ? onpen : offpen); + + // diagonal-right-top bar + draw_segment_diagonal_1(*tempbitmap, + bmwidth/2 + segwidth/2 + segwidth/5, bmwidth - segwidth - segwidth/5, + 0 + segwidth + segwidth/3, bmheight/2 - segwidth/2 - segwidth/3, + segwidth, (pattern & (1 << 14)) ? onpen : offpen); + + // diagonal-right-bottom bar + draw_segment_diagonal_2(*tempbitmap, + bmwidth/2 + segwidth/2 + segwidth/5, bmwidth - segwidth - segwidth/5, + bmheight/2 + segwidth/2 + segwidth/3, bmheight - segwidth - segwidth/3, + segwidth, (pattern & (1 << 15)) ? onpen : offpen); + + // decimal point + draw_segment_decimal(*tempbitmap, bmwidth + segwidth/2, bmheight - segwidth/2, segwidth, (pattern & (1 << 16)) ? onpen : offpen); + + // comma tail + draw_segment_diagonal_1(*tempbitmap, + bmwidth - (segwidth/2), bmwidth + segwidth, + bmheight - (segwidth), bmheight + segwidth*1.5, + segwidth/2, (pattern & (1 << 17)) ? onpen : offpen); + + // apply skew + apply_skew(*tempbitmap, 40); + + // resample to the target size + render_resample_argb_bitmap_hq(dest.base, dest.rowpixels, dest.width, dest.height, tempbitmap, NULL, &m_color); + + global_free(tempbitmap); +} + + +//------------------------------------------------- +// draw_dotmatrix - draw a row of 8 dots for a +// dotmatrix +//------------------------------------------------- + +void layout_element::component::draw_dotmatrix(bitmap_t &dest, const rectangle &bounds, int pattern) +{ + const rgb_t onpen = MAKE_ARGB(0xff, 0xff, 0xff, 0xff); + const rgb_t offpen = MAKE_ARGB(0xff, 0x20, 0x20, 0x20); + + // sizes for computation + int bmwidth = 2000; + int bmheight = 300; + int dotwidth = 250; + + // allocate a temporary bitmap for drawing + bitmap_t *tempbitmap = global_alloc(bitmap_t(bmwidth, bmheight, BITMAP_FORMAT_ARGB32)); + bitmap_fill(tempbitmap, NULL, MAKE_ARGB(0xff, 0x00, 0x00, 0x00)); + + for (int i = 0; i < 8; i++) + draw_segment_decimal(*tempbitmap, ((dotwidth/2 )+ (i * dotwidth)), bmheight/2, dotwidth, (pattern & (1 << i))?onpen:offpen); + + // resample to the target size + render_resample_argb_bitmap_hq(dest.base, dest.rowpixels, dest.width, dest.height, tempbitmap, NULL, &m_color); + + global_free(tempbitmap); +} + + +//------------------------------------------------- +// draw_segment_horizontal_caps - draw a +// horizontal LED segment with definable end +// and start points +//------------------------------------------------- + +void layout_element::component::draw_segment_horizontal_caps(bitmap_t &dest, int minx, int maxx, int midy, int width, int caps, rgb_t color) +{ + // loop over the width of the segment + for (int y = 0; y < width / 2; y++) { - bounds->x0 = bounds->y0 = 0.0f; - bounds->x1 = bounds->y1 = 1.0f; - return 0; + UINT32 *d0 = BITMAP_ADDR32(&dest, midy - y, 0); + UINT32 *d1 = BITMAP_ADDR32(&dest, midy + y, 0); + int ty = (y < width / 8) ? width / 8 : y; + + // loop over the length of the segment + for (int x = minx + ((caps & LINE_CAP_START) ? ty : 0); x < maxx - ((caps & LINE_CAP_END) ? ty : 0); x++) + d0[x] = d1[x] = color; + } +} + + +//------------------------------------------------- +// draw_segment_horizontal - draw a horizontal +// LED segment +//------------------------------------------------- + +void layout_element::component::draw_segment_horizontal(bitmap_t &dest, int minx, int maxx, int midy, int width, rgb_t color) +{ + draw_segment_horizontal_caps(dest, minx, maxx, midy, width, LINE_CAP_START | LINE_CAP_END, color); +} + + +//------------------------------------------------- +// draw_segment_vertical_caps - draw a +// vertical LED segment with definable end +// and start points +//------------------------------------------------- + +void layout_element::component::draw_segment_vertical_caps(bitmap_t &dest, int miny, int maxy, int midx, int width, int caps, rgb_t color) +{ + // loop over the width of the segment + for (int x = 0; x < width / 2; x++) + { + UINT32 *d0 = BITMAP_ADDR32(&dest, 0, midx - x); + UINT32 *d1 = BITMAP_ADDR32(&dest, 0, midx + x); + int tx = (x < width / 8) ? width / 8 : x; + + // loop over the length of the segment + for (int y = miny + ((caps & LINE_CAP_START) ? tx : 0); y < maxy - ((caps & LINE_CAP_END) ? tx : 0); y++) + d0[y * dest.rowpixels] = d1[y * dest.rowpixels] = color; + } +} + + +//------------------------------------------------- +// draw_segment_vertical - draw a vertical +// LED segment +//------------------------------------------------- + +void layout_element::component::draw_segment_vertical(bitmap_t &dest, int miny, int maxy, int midx, int width, rgb_t color) +{ + draw_segment_vertical_caps(dest, miny, maxy, midx, width, LINE_CAP_START | LINE_CAP_END, color); +} + + +//------------------------------------------------- +// draw_segment_diagonal_1 - draw a diagonal +// LED segment that looks like this: / +//------------------------------------------------- + +void layout_element::component::draw_segment_diagonal_1(bitmap_t &dest, int minx, int maxx, int miny, int maxy, int width, rgb_t color) +{ + // compute parameters + width *= 1.5; + float ratio = (maxy - miny - width) / (float)(maxx - minx); + + // draw line + for (int x = minx; x < maxx; x++) + if (x >= 0 && x < dest.width) + { + UINT32 *d = BITMAP_ADDR32(&dest, 0, x); + int step = (x - minx) * ratio; + + for (int y = maxy - width - step; y < maxy - step; y++) + if (y >= 0 && y < dest.height) + d[y * dest.rowpixels] = color; + } +} + + +//------------------------------------------------- +// draw_segment_diagonal_2 - draw a diagonal +// LED segment that looks like this: +//------------------------------------------------- + +void layout_element::component::draw_segment_diagonal_2(bitmap_t &dest, int minx, int maxx, int miny, int maxy, int width, rgb_t color) +{ + // compute parameters + width *= 1.5; + float ratio = (maxy - miny - width) / (float)(maxx - minx); + + // draw line + for (int x = minx; x < maxx; x++) + if (x >= 0 && x < dest.width) + { + UINT32 *d = BITMAP_ADDR32(&dest, 0, x); + int step = (x - minx) * ratio; + + for (int y = miny + step; y < miny + step + width; y++) + if (y >= 0 && y < dest.height) + d[y * dest.rowpixels] = color; + } +} + + +//------------------------------------------------- +// draw_segment_decimal - draw a decimal point +//------------------------------------------------- + +void layout_element::component::draw_segment_decimal(bitmap_t &dest, int midx, int midy, int width, rgb_t color) +{ + // compute parameters + width /= 2; + float ooradius2 = 1.0f / (float)(width * width); + + // iterate over y + for (UINT32 y = 0; y <= width; y++) + { + UINT32 *d0 = BITMAP_ADDR32(&dest, midy - y, 0); + UINT32 *d1 = BITMAP_ADDR32(&dest, midy + y, 0); + float xval = width * sqrt(1.0f - (float)(y * y) * ooradius2); + INT32 left, right; + + // compute left/right coordinates + left = midx - (INT32)(xval + 0.5f); + right = midx + (INT32)(xval + 0.5f); + + // draw this scanline + for (UINT32 x = left; x < right; x++) + d0[x] = d1[x] = color; + } +} + + +//------------------------------------------------- +// draw_segment_comma - draw a comma tail +//------------------------------------------------- + +void layout_element::component::draw_segment_comma(bitmap_t &dest, int minx, int maxx, int miny, int maxy, int width, rgb_t color) +{ + // compute parameters + width *= 1.5; + float ratio = (maxy - miny - width) / (float)(maxx - minx); + + // draw line + for (int x = minx; x < maxx; x++) + { + UINT32 *d = BITMAP_ADDR32(&dest, 0, x); + int step = (x - minx) * ratio; + + for (int y = maxy; y < maxy - width - step; y--) + d[y * dest.rowpixels] = color; + } +} + + +//------------------------------------------------- +// apply_skew - apply skew to a bitmap_t +//------------------------------------------------- + +void layout_element::component::apply_skew(bitmap_t &dest, int skewwidth) +{ + for (int y = 0; y < dest.height; y++) + { + UINT32 *destrow = BITMAP_ADDR32(&dest, y, 0); + int offs = skewwidth * (dest.height - y) / dest.height; + for (int x = dest.width - skewwidth - 1; x >= 0; x--) + destrow[x + offs] = destrow[x]; + for (int x = 0; x < offs; x++) + destrow[x] = 0; + } +} + + + +//************************************************************************** +// LAYOUT VIEW +//************************************************************************** + +//------------------------------------------------- +// layout_view - constructor +//------------------------------------------------- + +layout_view::layout_view(running_machine &machine, xml_data_node &viewnode, simple_list &elemlist) + : m_next(NULL), + m_aspect(1.0f), + m_scraspect(1.0f), + m_screens(machine.m_respool), + m_backdrop_list(machine.m_respool), + m_screen_list(machine.m_respool), + m_overlay_list(machine.m_respool), + m_bezel_list(machine.m_respool) +{ + // allocate a copy of the name + m_name = xml_get_attribute_string_with_subst(machine, viewnode, "name", ""); + + // if we have a bounds item, load it + xml_data_node *boundsnode = xml_get_sibling(viewnode.child, "bounds"); + m_expbounds.x0 = m_expbounds.y0 = m_expbounds.x1 = m_expbounds.y1 = 0; + if (boundsnode != NULL) + parse_bounds(machine, xml_get_sibling(boundsnode, "bounds"), m_expbounds); + + // load backdrop items + for (xml_data_node *itemnode = xml_get_sibling(viewnode.child, "backdrop"); itemnode != NULL; itemnode = xml_get_sibling(itemnode->next, "backdrop")) + m_backdrop_list.append(*auto_alloc(&machine, item(machine, *itemnode, elemlist))); + + // load screen items + for (xml_data_node *itemnode = xml_get_sibling(viewnode.child, "screen"); itemnode != NULL; itemnode = xml_get_sibling(itemnode->next, "screen")) + m_screen_list.append(*auto_alloc(&machine, item(machine, *itemnode, elemlist))); + + // load overlay items + for (xml_data_node *itemnode = xml_get_sibling(viewnode.child, "overlay"); itemnode != NULL; itemnode = xml_get_sibling(itemnode->next, "overlay")) + m_overlay_list.append(*auto_alloc(&machine, item(machine, *itemnode, elemlist))); + + // load bezel items + for (xml_data_node *itemnode = xml_get_sibling(viewnode.child, "bezel"); itemnode != NULL; itemnode = xml_get_sibling(itemnode->next, "bezel")) + m_bezel_list.append(*auto_alloc(&machine, item(machine, *itemnode, elemlist))); + + // recompute the data for the view based on a default layer config + recompute(render_layer_config()); +} + + +//------------------------------------------------- +// layout_view - destructor +//------------------------------------------------- + +layout_view::~layout_view() +{ +} + + +//------------------------------------------------- +// first_item - return the first item in the +// appropriate list +//------------------------------------------------- + +layout_view::item *layout_view::first_item(item_layer layer) const +{ + switch (layer) + { + case ITEM_LAYER_BACKDROP: return m_backdrop_list.first(); + case ITEM_LAYER_SCREEN: return m_screen_list.first(); + case ITEM_LAYER_OVERLAY: return m_overlay_list.first(); + case ITEM_LAYER_BEZEL: return m_bezel_list.first(); + default: return NULL; + } +} + + +//------------------------------------------------- +// recompute - recompute the bounds and aspect +// ratio of a view and all of its contained items +//------------------------------------------------- + +void layout_view::recompute(render_layer_config layerconfig) +{ + // reset the bounds + m_bounds.x0 = m_bounds.y0 = m_bounds.x1 = m_bounds.y1 = 0.0f; + m_scrbounds.x0 = m_scrbounds.y0 = m_scrbounds.x1 = m_scrbounds.y1 = 0.0f; + m_screens.reset(); + + // loop over all layers + bool first = true; + bool scrfirst = true; + for (item_layer layer = ITEM_LAYER_FIRST; layer < ITEM_LAYER_MAX; layer++) + { + // determine if this layer should be visible + switch (layer) + { + case ITEM_LAYER_BACKDROP: m_layenabled[layer] = layerconfig.backdrops_enabled(); break; + case ITEM_LAYER_OVERLAY: m_layenabled[layer] = layerconfig.overlays_enabled(); break; + case ITEM_LAYER_BEZEL: m_layenabled[layer] = layerconfig.bezels_enabled(); break; + default: m_layenabled[layer] = true; break; + } + + // only do it if requested + if (m_layenabled[layer]) + for (item *curitem = first_item(layer); curitem != NULL; curitem = curitem->next()) + { + // accumulate bounds + if (first) + m_bounds = curitem->m_rawbounds; + else + union_render_bounds(&m_bounds, &curitem->m_rawbounds); + first = false; + + // accumulate screen bounds + if (curitem->m_screen != NULL) + { + if (scrfirst) + m_scrbounds = curitem->m_rawbounds; + else + union_render_bounds(&m_scrbounds, &curitem->m_rawbounds); + scrfirst = false; + + // accumulate the screens in use while we're scanning + m_screens.add(*curitem->m_screen); + } + } } - /* parse out the data */ - if (xml_get_attribute(boundsnode, "left") != NULL) + // if we have an explicit bounds, override it + if (m_expbounds.x1 > m_expbounds.x0) + m_bounds = m_expbounds; + + // compute the aspect ratio of the view + m_aspect = (m_bounds.x1 - m_bounds.x0) / (m_bounds.y1 - m_bounds.y0); + m_scraspect = (m_scrbounds.x1 - m_scrbounds.x0) / (m_scrbounds.y1 - m_scrbounds.y0); + + // if we're handling things normally, the target bounds are (0,0)-(1,1) + render_bounds target_bounds; + if (!layerconfig.zoom_to_screen() || m_screens.count() == 0) { - /* left/right/top/bottom format */ - bounds->x0 = xml_get_attribute_float_with_subst(machine, boundsnode, "left", 0.0f); - bounds->x1 = xml_get_attribute_float_with_subst(machine, boundsnode, "right", 1.0f); - bounds->y0 = xml_get_attribute_float_with_subst(machine, boundsnode, "top", 0.0f); - bounds->y1 = xml_get_attribute_float_with_subst(machine, boundsnode, "bottom", 1.0f); + target_bounds.x0 = target_bounds.y0 = 0.0f; + target_bounds.x1 = target_bounds.y1 = 1.0f; } - else if (xml_get_attribute(boundsnode, "x") != NULL) + + // if we're cropping, we want the screen area to fill (0,0)-(1,1) + else { - /* x/y/width/height format */ - bounds->x0 = xml_get_attribute_float_with_subst(machine, boundsnode, "x", 0.0f); - bounds->x1 = bounds->x0 + xml_get_attribute_float_with_subst(machine, boundsnode, "width", 1.0f); - bounds->y0 = xml_get_attribute_float_with_subst(machine, boundsnode, "y", 0.0f); - bounds->y1 = bounds->y0 + xml_get_attribute_float_with_subst(machine, boundsnode, "height", 1.0f); + float targwidth = (m_bounds.x1 - m_bounds.x0) / (m_scrbounds.x1 - m_scrbounds.x0); + float targheight = (m_bounds.y1 - m_bounds.y0) / (m_scrbounds.y1 - m_scrbounds.y0); + target_bounds.x0 = (m_bounds.x0 - m_scrbounds.x0) / (m_bounds.x1 - m_bounds.x0) * targwidth; + target_bounds.y0 = (m_bounds.y0 - m_scrbounds.y0) / (m_bounds.y1 - m_bounds.y0) * targheight; + target_bounds.x1 = target_bounds.x0 + targwidth; + target_bounds.y1 = target_bounds.y0 + targheight; + } + + // determine the scale/offset for normalization + float xoffs = m_bounds.x0; + float yoffs = m_bounds.y0; + float xscale = (target_bounds.x1 - target_bounds.x0) / (m_bounds.x1 - m_bounds.x0); + float yscale = (target_bounds.y1 - target_bounds.y0) / (m_bounds.y1 - m_bounds.y0); + + // normalize all the item bounds + for (item_layer layer = ITEM_LAYER_FIRST; layer < ITEM_LAYER_MAX; layer++) + for (item *curitem = first_item(layer); curitem != NULL; curitem = curitem->next()) + { + curitem->m_bounds.x0 = target_bounds.x0 + (curitem->m_rawbounds.x0 - xoffs) * xscale; + curitem->m_bounds.x1 = target_bounds.x0 + (curitem->m_rawbounds.x1 - xoffs) * xscale; + curitem->m_bounds.y0 = target_bounds.y0 + (curitem->m_rawbounds.y0 - yoffs) * yscale; + curitem->m_bounds.y1 = target_bounds.y0 + (curitem->m_rawbounds.y1 - yoffs) * yscale; + } +} + + + +//************************************************************************** +// LAYOUT VIEW ITEM +//************************************************************************** + +//------------------------------------------------- +// item - constructor +//------------------------------------------------- + +layout_view::item::item(running_machine &machine, xml_data_node &itemnode, simple_list &elemlist) + : m_next(NULL), + m_element(NULL), + m_input_mask(0), + m_screen(NULL), + m_orientation(ROT0) +{ + // allocate a copy of the output name + m_output_name = xml_get_attribute_string_with_subst(machine, itemnode, "name", ""); + + // allocate a copy of the input tag + m_input_tag = xml_get_attribute_string_with_subst(machine, itemnode, "inputtag", ""); + + // find the associated element + const char *name = xml_get_attribute_string_with_subst(machine, itemnode, "element", NULL); + if (name != NULL) + { + // search the list of elements for a match + for (m_element = elemlist.first(); m_element != NULL; m_element = m_element->next()) + if (strcmp(name, m_element->name()) == 0) + break; + + // error if not found + if (m_element == NULL) + throw emu_fatalerror("Unable to find layout element %s", name); + } + + // fetch common data + int index = xml_get_attribute_int_with_subst(machine, itemnode, "index", -1); + if (index != -1) + m_screen = downcast(machine.m_devicelist.find(SCREEN, index)); + m_input_mask = xml_get_attribute_int_with_subst(machine, itemnode, "inputmask", 0); + if (m_output_name[0] != 0 && m_element != NULL) + output_set_value(m_output_name, m_element->default_state()); + parse_bounds(machine, xml_get_sibling(itemnode.child, "bounds"), m_rawbounds); + parse_color(machine, xml_get_sibling(itemnode.child, "color"), m_color); + parse_orientation(machine, xml_get_sibling(itemnode.child, "orientation"), m_orientation); + + // sanity checks + if (strcmp(itemnode.name, "screen") == 0) + { + if (m_screen == NULL) + throw emu_fatalerror("Layout references invalid screen index %d", index); } else { - fatalerror("Illegal bounds value in XML"); - return 1; + if (m_element == NULL) + throw emu_fatalerror("Layout item of type %s require an element tag", itemnode.name); } - - /* check for errors */ - if (bounds->x0 > bounds->x1 || bounds->y0 > bounds->y1) - { - fatalerror("Illegal bounds value in XML: (%f-%f)-(%f-%f)", bounds->x0, bounds->x1, bounds->y0, bounds->y1); - return 1; - } - return 0; } -/*------------------------------------------------- - load_color - parse a color XML node --------------------------------------------------*/ +//------------------------------------------------- +// item - destructor +//------------------------------------------------- -static int load_color(running_machine &machine, xml_data_node *colornode, render_color *color) +layout_view::item::~item() { - /* skip if nothing */ - if (colornode == NULL) - { - color->r = color->g = color->b = color->a = 1.0f; - return 0; - } - - /* parse out the data */ - color->r = xml_get_attribute_float_with_subst(machine, colornode, "red", 1.0); - color->g = xml_get_attribute_float_with_subst(machine, colornode, "green", 1.0); - color->b = xml_get_attribute_float_with_subst(machine, colornode, "blue", 1.0); - color->a = xml_get_attribute_float_with_subst(machine, colornode, "alpha", 1.0); - - /* check for errors */ - if (color->r < 0.0 || color->r > 1.0 || color->g < 0.0 || color->g > 1.0 || - color->b < 0.0 || color->b > 1.0 || color->a < 0.0 || color->a > 1.0) - { - fatalerror("Illegal ARGB color value in XML: %f,%f,%f,%f", color->r, color->g, color->b, color->a); - return 1; - } - return 0; } -/*------------------------------------------------- - load_orientation - parse an orientation XML - node --------------------------------------------------*/ +//------------------------------------------------- +// state - fetch state based on configured source +//------------------------------------------------- -static int load_orientation(running_machine &machine, xml_data_node *orientnode, int *orientation) +int layout_view::item::state() const { - int rotate; - - /* skip if nothing */ - if (orientnode == NULL) + int state = 0; + + assert(m_element != NULL); + + // if configured to an output, fetch the output value + if (m_output_name[0] != 0) + state = output_get_value(m_output_name); + + // if configured to an input, fetch the input value + else if (m_input_tag[0] != 0) { - *orientation = ROT0; - return 0; + const input_field_config *field = input_field_by_tag_and_mask(m_element->machine().m_portlist, m_input_tag, m_input_mask); + if (field != NULL) + state = ((input_port_read_safe(&m_element->machine(), m_input_tag, 0) ^ field->defvalue) & m_input_mask) ? 1 : 0; } - - /* parse out the data */ - rotate = xml_get_attribute_int_with_subst(machine, orientnode, "rotate", 0); - switch (rotate) - { - case 0: *orientation = ROT0; break; - case 90: *orientation = ROT90; break; - case 180: *orientation = ROT180; break; - case 270: *orientation = ROT270; break; - default: - fatalerror("Invalid rotation in XML orientation node: %d", rotate); - return 1; - } - if (strcmp("yes", xml_get_attribute_string_with_subst(machine, orientnode, "swapxy", "no")) == 0) - *orientation ^= ORIENTATION_SWAP_XY; - if (strcmp("yes", xml_get_attribute_string_with_subst(machine, orientnode, "flipx", "no")) == 0) - *orientation ^= ORIENTATION_FLIP_X; - if (strcmp("yes", xml_get_attribute_string_with_subst(machine, orientnode, "flipy", "no")) == 0) - *orientation ^= ORIENTATION_FLIP_Y; - return 0; + return state; } -/*------------------------------------------------- - layout_file_free - free memory for a - layout_file and all of its subelements --------------------------------------------------*/ -void layout_file_free(layout_file *file) +//************************************************************************** +// LAYOUT FILE +//************************************************************************** + +//------------------------------------------------- +// layout_file - constructor +//------------------------------------------------- + +layout_file::layout_file(running_machine &machine, xml_data_node &rootnode, const char *dirname) + : m_next(NULL), + m_elemlist(machine.m_respool), + m_viewlist(machine.m_respool) { - /* free each element in the list */ - while (file->elemlist != NULL) - { - layout_element *temp = file->elemlist; - file->elemlist = temp->next; - layout_element_free(temp); - } + // find the layout node + xml_data_node *mamelayoutnode = xml_get_sibling(rootnode.child, "mamelayout"); + if (mamelayoutnode == NULL) + throw emu_fatalerror("Invalid XML file: missing mamelayout node"); - /* free each layout */ - while (file->viewlist != NULL) - { - layout_view *temp = file->viewlist; - file->viewlist = temp->next; - layout_view_free(temp); - } + // validate the config data version + int version = xml_get_attribute_int(mamelayoutnode, "version", 0); + if (version != LAYOUT_VERSION) + throw emu_fatalerror("Invalid XML file: unsupported version"); - /* free the file itself */ - global_free(file); + // parse all the elements + for (xml_data_node *elemnode = xml_get_sibling(mamelayoutnode->child, "element"); elemnode != NULL; elemnode = xml_get_sibling(elemnode->next, "element")) + m_elemlist.append(*auto_alloc(&machine, layout_element(machine, *elemnode, dirname))); + + // parse all the views + for (xml_data_node *viewnode = xml_get_sibling(mamelayoutnode->child, "view"); viewnode != NULL; viewnode = xml_get_sibling(viewnode->next, "view")) + m_viewlist.append(*auto_alloc(&machine, layout_view(machine, *viewnode, m_elemlist))); } -/*------------------------------------------------- - layout_view_free - free memory for a - layout_view and all of its subelements --------------------------------------------------*/ +//------------------------------------------------- +// ~layout_file - destructor +//------------------------------------------------- -static void layout_view_free(layout_view *view) +layout_file::~layout_file() { - int layer; - - /* for each layer, free each item in that layer */ - for (layer = 0; layer < ITEM_LAYER_MAX; layer++) - while (view->itemlist[layer] != NULL) - { - view_item *temp = view->itemlist[layer]; - view->itemlist[layer] = temp->next; - if (temp->output_name != NULL) - global_free(temp->output_name); - if (temp->input_tag != NULL) - global_free(temp->input_tag); - global_free(temp); - } - - /* free the view itself */ - if (view->name != NULL) - global_free((void *)view->name); - global_free(view); -} - - -/*------------------------------------------------- - layout_element_free - free memory for a - layout_element and its components --------------------------------------------------*/ - -static void layout_element_free(layout_element *element) -{ - /* free all allocated components */ - while (element->complist != NULL) - { - element_component *temp = element->complist; - element->complist = temp->next; - if (temp->string != NULL) - global_free(temp->string); - if (temp->dirname != NULL) - global_free(temp->dirname); - if (temp->imagefile != NULL) - global_free(temp->imagefile); - if (temp->alphafile != NULL) - global_free(temp->alphafile); - global_free(temp->bitmap); - global_free(temp); - } - - /* free all textures */ - if (element->elemtex != NULL) - { - int state; - - /* loop over all states and free their textures */ - for (state = 0; state <= element->maxstate; state++) - element->machine->render().texture_free(element->elemtex[state].texture); - - global_free(element->elemtex); - } - - /* free the element itself */ - if (element->name != NULL) - global_free(element->name); - global_free(element); } diff --git a/src/emu/rendlay.h b/src/emu/rendlay.h index 1a040c85f10..2b25d11d5be 100644 --- a/src/emu/rendlay.h +++ b/src/emu/rendlay.h @@ -4,8 +4,36 @@ Core rendering layout parser and manager. - Copyright Nicola Salmoria and the MAME Team. - Visit http://mamedev.org for licensing and usage restrictions. +**************************************************************************** + + Copyright Aaron Giles + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name 'MAME' nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. ***************************************************************************/ @@ -14,206 +42,281 @@ #include "render.h" -#include +//************************************************************************** +// CONSTANTS +//************************************************************************** - -/*************************************************************************** - - Theory of operation - ------------------- - - A render "target" is described by 5 parameters: - - - width = width, in pixels - - height = height, in pixels - - bpp = depth, in bits per pixel - - orientation = orientation of the target - - pixel_aspect = aspect ratio of the pixels - - Width, height, and bpp are self-explanatory. The remaining parameters - need some additional explanation. - - Regarding orientation, there are three orientations that need to be - dealt with: target orientation, UI orientation, and game orientation. - In the current model, the UI orientation tracks the target orientation - so that the UI is (in theory) facing the correct direction. The game - orientation is specified by the game driver and indicates how the - game and artwork are rotated. - - Regarding pixel_aspect, this is the aspect ratio of the individual - pixels, not the aspect ratio of the screen. You can determine this by - dividing the aspect ratio of the screen by the aspect ratio of the - resolution. For example, a 4:3 screen displaying 640x480 gives a - pixel aspect ratio of (4/3)/(640/480) = 1.0, meaning the pixels are - square. That same screen displaying 1280x1024 would have a pixel - aspect ratio of (4/3)/(1280/1024) = 1.06666, meaning the pixels are - slightly wider than they are tall. - - Artwork is always assumed to be a 1.0 pixel aspect ratio. The game - screens themselves can be variable aspect ratios. - -***************************************************************************/ - - -/*************************************************************************** - CONSTANTS -***************************************************************************/ - -enum +enum item_layer { - ITEM_LAYER_BACKDROP = 0, + ITEM_LAYER_FIRST = 0, + ITEM_LAYER_BACKDROP = ITEM_LAYER_FIRST, ITEM_LAYER_SCREEN, ITEM_LAYER_OVERLAY, ITEM_LAYER_BEZEL, ITEM_LAYER_MAX }; +DECLARE_ENUM_OPERATORS(item_layer); -/*************************************************************************** - TYPE DEFINITIONS -***************************************************************************/ +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** -typedef struct _element_component element_component; -typedef struct _element_texture element_texture; -typedef struct _layout_element layout_element; -typedef struct _view_item_state view_item_state; -typedef struct _view_item view_item; -typedef struct _layout_view layout_view; -typedef struct _layout_file layout_file; -/* an element_texture encapsulates a texture for a given element in a given state */ -struct _element_texture +// ======================> layout_element + +// a layout_element is a single named element, which may have multiple components +class layout_element { - layout_element * element; /* pointer back to the element */ - render_texture * texture; /* texture for this state */ - int state; /* associated state number */ + friend class simple_list; + +public: + // construction/destruction + layout_element(running_machine &machine, xml_data_node &elemnode, const char *dirname); + virtual ~layout_element(); + + // getters + layout_element *next() const { return m_next; } + const char *name() const { return m_name; } + running_machine &machine() const { return m_machine; } + int default_state() const { return m_defstate; } + int maxstate() const { return m_maxstate; } + render_texture *state_texture(int state); + +private: + // a component represents an image, rectangle, or disk in an element + class component + { + friend class layout_element; + friend class simple_list; + + public: + // construction/destruction + component(running_machine &machine, xml_data_node &compnode, const char *dirname); + ~component(); + + // getters + component *next() const { return m_next; } + const render_bounds &bounds() const { return m_bounds; } + + // operations + void draw(running_machine &machine, bitmap_t &dest, const rectangle &bounds, int state); + + private: + // component types + enum component_type + { + CTYPE_INVALID = 0, + CTYPE_IMAGE, + CTYPE_RECT, + CTYPE_DISK, + CTYPE_TEXT, + CTYPE_LED7SEG, + CTYPE_LED14SEG, + CTYPE_LED16SEG, + CTYPE_LED14SEGSC, + CTYPE_LED16SEGSC, + CTYPE_DOTMATRIX, + CTYPE_MAX + }; + + // helpers + void draw_rect(bitmap_t &dest, const rectangle &bounds); + void draw_disk(bitmap_t &dest, const rectangle &bounds); + void draw_text(running_machine &machine, bitmap_t &dest, const rectangle &bounds); + bitmap_t *load_bitmap(); + void draw_led7seg(bitmap_t &dest, const rectangle &bounds, int pattern); + void draw_led14seg(bitmap_t &dest, const rectangle &bounds, int pattern); + void draw_led14segsc(bitmap_t &dest, const rectangle &bounds, int pattern); + void draw_led16seg(bitmap_t &dest, const rectangle &bounds, int pattern); + void draw_led16segsc(bitmap_t &dest, const rectangle &bounds, int pattern); + void draw_dotmatrix(bitmap_t &dest, const rectangle &bounds, int pattern); + void draw_segment_horizontal_caps(bitmap_t &dest, int minx, int maxx, int midy, int width, int caps, rgb_t color); + void draw_segment_horizontal(bitmap_t &dest, int minx, int maxx, int midy, int width, rgb_t color); + void draw_segment_vertical_caps(bitmap_t &dest, int miny, int maxy, int midx, int width, int caps, rgb_t color); + void draw_segment_vertical(bitmap_t &dest, int miny, int maxy, int midx, int width, rgb_t color); + void draw_segment_diagonal_1(bitmap_t &dest, int minx, int maxx, int miny, int maxy, int width, rgb_t color); + void draw_segment_diagonal_2(bitmap_t &dest, int minx, int maxx, int miny, int maxy, int width, rgb_t color); + void draw_segment_decimal(bitmap_t &dest, int midx, int midy, int width, rgb_t color); + void draw_segment_comma(bitmap_t &dest, int minx, int maxx, int miny, int maxy, int width, rgb_t color); + void apply_skew(bitmap_t &dest, int skewwidth); + + // internal state + component * m_next; // link to next component + component_type m_type; // type of component + int m_state; // state where this component is visible (-1 means all states) + render_bounds m_bounds; // bounds of the element + render_color m_color; // color of the element + astring m_string; // string for text components + bitmap_t * m_bitmap; // source bitmap for images + astring m_dirname; // directory name of image file (for lazy loading) + astring m_imagefile; // name of the image file (for lazy loading) + astring m_alphafile; // name of the alpha file (for lazy loading) + bool m_hasalpha; // is there any alpha component present? + }; + + // a texture encapsulates a texture for a given element in a given state + class texture + { + public: + texture(); + ~texture(); + + layout_element * m_element; // pointer back to the element + render_texture * m_texture; // texture for this state + int m_state; // associated state number + }; + + // internal helpers + static void element_scale(bitmap_t &dest, const bitmap_t &source, const rectangle &sbounds, void *param); + + // internal state + layout_element * m_next; // link to next element + running_machine & m_machine; // reference to the owning machine + astring m_name; // name of this element + simple_list m_complist; // list of components + int m_defstate; // default state of this element + int m_maxstate; // maximum state value for all components + texture * m_elemtex; // array of element textures used for managing the scaled bitmaps }; -/* a layout_element is a single named element, which may have multiple components */ -struct _layout_element +// ======================> layout_view + +// a layout_view encapsulates a named list of items +class layout_view { - layout_element * next; /* link to next element */ - running_machine * machine; - const char * name; /* name of this element */ - element_component * complist; /* head of the list of components */ - int defstate; /* default state of this element */ - int maxstate; /* maximum state value for all components */ - element_texture * elemtex; /* array of element textures used for managing the scaled bitmaps */ + friend class simple_list; + +public: + // an item is a single backdrop, screen, overlay, or bezel item + class item + { + friend class layout_view; + friend class simple_list; + + public: + // construction/destruction + item(running_machine &machine, xml_data_node &itemnode, simple_list &elemlist); + virtual ~item(); + + // getters + item *next() const { return m_next; } + layout_element *element() const { return m_element; } + screen_device *screen() { return m_screen; } + const render_bounds &bounds() const { return m_bounds; } + const render_color &color() const { return m_color; } + int orientation() const { return m_orientation; } + render_container *screen_container(running_machine &machine) const { return (m_screen != NULL) ? &m_screen->container() : NULL; } + bool has_input() const { return bool(m_input_tag); } + const char *input_tag_and_mask(UINT32 &mask) const { mask = m_input_mask; return m_input_tag; } + + // fetch state based on configured source + int state() const; + + private: + // internal state + item * m_next; // link to next item + layout_element * m_element; // pointer to the associated element (non-screens only) + astring m_output_name; // name of this item + astring m_input_tag; // input tag of this item + UINT32 m_input_mask; // input mask of this item + screen_device * m_screen; // pointer to screen + int m_orientation; // orientation of this item + render_bounds m_bounds; // bounds of the item + render_bounds m_rawbounds; // raw (original) bounds of the item + render_color m_color; // color of the item + }; + + // construction/destruction + layout_view(running_machine &machine, xml_data_node &viewnode, simple_list &elemlist); + virtual ~layout_view(); + + // getters + layout_view *next() const { return m_next; } + item *first_item(item_layer layer) const; + const char *name() const { return m_name; } + const render_screen_list &screens() const { return m_screens; } + bool layer_enabled(item_layer layer) const { return m_layenabled[layer]; } + + // + bool has_art() const { return (m_backdrop_list.count() + m_overlay_list.count() + m_bezel_list.count() != 0); } + float effective_aspect(render_layer_config config) const { return (config.zoom_to_screen() && m_screens.count() != 0) ? m_scraspect : m_aspect; } + + // operations + void recompute(render_layer_config layerconfig); + +private: + // internal state + layout_view * m_next; // pointer to next layout in the list + astring m_name; // name of the layout + float m_aspect; // X/Y of the layout + float m_scraspect; // X/Y of the screen areas + render_screen_list m_screens; // list of active screens + render_bounds m_bounds; // computed bounds of the view + render_bounds m_scrbounds; // computed bounds of the screens within the view + render_bounds m_expbounds; // explicit bounds of the view + bool m_layenabled[ITEM_LAYER_MAX]; // is this layer enabled? + simple_list m_backdrop_list; // list of backdrop items + simple_list m_screen_list; // list of screen items + simple_list m_overlay_list; // list of overlay items + simple_list m_bezel_list; // list of bezel items }; -/* a view_item_state contains the string-tagged state of a view item */ -struct _view_item_state +// ======================> layout_file + +// a layout_file consists of a list of elements and a list of views +class layout_file { - view_item_state * next; /* pointer to the next one */ - const char * name; /* string that was set */ - int curstate; /* current state */ -}; + friend class simple_list; + +public: + // construction/destruction + layout_file(running_machine &machine, xml_data_node &rootnode, const char *dirname); + virtual ~layout_file(); + // getters + layout_file *next() const { return m_next; } + layout_element *first_element() const { return m_elemlist.first(); } + layout_view *first_view() const { return m_viewlist.first(); } -/* a view_item is a single backdrop, screen, overlay, or bezel item */ -struct _view_item -{ - view_item * next; /* link to next item */ - layout_element * element; /* pointer to the associated element (non-screens only) */ - const char * output_name; /* name of this item */ - const char * input_tag; /* input tag of this item */ - UINT32 input_mask; /* input mask of this item */ - int index; /* index for this item (screens only) */ - int orientation; /* orientation of this item */ - render_bounds bounds; /* bounds of the item */ - render_bounds rawbounds; /* raw (original) bounds of the item */ - render_color color; /* color of the item */ -}; - - -/* a layout_view encapsulates a named list of items */ -struct _layout_view -{ - layout_view * next; /* pointer to next layout in the list */ - const char * name; /* name of the layout */ - float aspect; /* X/Y of the layout */ - float scraspect; /* X/Y of the screen areas */ - UINT32 screens; /* bitmask of screens used */ - render_bounds bounds; /* computed bounds of the view */ - render_bounds scrbounds; /* computed bounds of the screens within the view */ - render_bounds expbounds; /* explicit bounds of the view */ - UINT8 layenabled[ITEM_LAYER_MAX]; /* is this layer enabled? */ - view_item * itemlist[ITEM_LAYER_MAX]; /* list of layout items for each layer */ -}; - - -/* a layout_file consists of a list of elements and a list of views */ -struct _layout_file -{ - layout_file * next; /* pointer to the next file in the list */ - layout_element * elemlist; /* list of shared layout elements */ - layout_view * viewlist; /* list of views */ +private: + // internal state + layout_file * m_next; // pointer to the next file in the list + simple_list m_elemlist; // list of shared layout elements + simple_list m_viewlist; // list of views }; -/*************************************************************************** - FUNCTION PROTOTYPES -***************************************************************************/ +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** -/* ----- layout views ----- */ -void layout_view_recompute(layout_view *view, int layerconfig); +// single screen layouts +extern const char layout_horizont[]; // horizontal 4:3 screens +extern const char layout_vertical[]; // vertical 4:3 screens + +// dual screen layouts +extern const char layout_dualhsxs[]; // dual 4:3 screens side-by-side +extern const char layout_dualhovu[]; // dual 4:3 screens above and below +extern const char layout_dualhuov[]; // dual 4:3 screens below and above + +// triple screen layouts +extern const char layout_triphsxs[]; // triple 4:3 screens side-by-side + +// generic color overlay layouts +extern const char layout_ho20ffff[]; // horizontal 4:3 with 20,FF,FF color overlay +extern const char layout_ho2eff2e[]; // horizontal 4:3 with 2E,FF,2E color overlay +extern const char layout_ho4f893d[]; // horizontal 4:3 with 4F,89,3D color overlay +extern const char layout_ho88ffff[]; // horizontal 4:3 with 88,FF,FF color overlay +extern const char layout_hoa0a0ff[]; // horizontal 4:3 with A0,A0,FF color overlay +extern const char layout_hoffe457[]; // horizontal 4:3 with FF,E4,57 color overlay +extern const char layout_hoffff20[]; // horizontal 4:3 with FF,FF,20 color overlay +extern const char layout_voffff20[]; // vertical 4:3 with FF,FF,20 color overlay -/* ----- layout file parsing ----- */ -layout_file *layout_file_load(running_machine &machine, const char *dirname, const char *filename); -void layout_file_free(layout_file *file); - - - -/*************************************************************************** - GLOBAL VARIABLES -***************************************************************************/ - -/* single screen layouts */ -extern const char layout_horizont[]; /* horizontal 4:3 screens */ -extern const char layout_vertical[]; /* vertical 4:3 screens */ - -/* dual screen layouts */ -extern const char layout_dualhsxs[]; /* dual 4:3 screens side-by-side */ -extern const char layout_dualhovu[]; /* dual 4:3 screens above and below */ -extern const char layout_dualhuov[]; /* dual 4:3 screens below and above */ - -/* triple screen layouts */ -extern const char layout_triphsxs[]; /* triple 4:3 screens side-by-side */ - -/* generic color overlay layouts */ -extern const char layout_ho20ffff[]; /* horizontal 4:3 with 20,FF,FF color overlay */ -extern const char layout_ho2eff2e[]; /* horizontal 4:3 with 2E,FF,2E color overlay */ -extern const char layout_ho4f893d[]; /* horizontal 4:3 with 4F,89,3D color overlay */ -extern const char layout_ho88ffff[]; /* horizontal 4:3 with 88,FF,FF color overlay */ -extern const char layout_hoa0a0ff[]; /* horizontal 4:3 with A0,A0,FF color overlay */ -extern const char layout_hoffe457[]; /* horizontal 4:3 with FF,E4,57 color overlay */ -extern const char layout_hoffff20[]; /* horizontal 4:3 with FF,FF,20 color overlay */ -extern const char layout_voffff20[]; /* vertical 4:3 with FF,FF,20 color overlay */ - - - -/*************************************************************************** - INLINE FUNCTIONS -***************************************************************************/ - -/*------------------------------------------------- - layout_view_has_art - true if a render_view contains - any non-screen elements --------------------------------------------------*/ - -INLINE int layout_view_has_art(layout_view *view) -{ - return (view->itemlist[ITEM_LAYER_BACKDROP] != 0 || - view->itemlist[ITEM_LAYER_OVERLAY] != 0 || - view->itemlist[ITEM_LAYER_BEZEL] != 0); -} - - - -#endif /* __RENDLAY_H__ */ +#endif // __RENDLAY_H__ diff --git a/src/emu/rendutil.c b/src/emu/rendutil.c index 8377a395a8f..c6c9dea23fc 100644 --- a/src/emu/rendutil.c +++ b/src/emu/rendutil.c @@ -23,8 +23,8 @@ /* utilities */ static void resample_argb_bitmap_average(UINT32 *dest, UINT32 drowpixels, UINT32 dwidth, UINT32 dheight, const UINT32 *source, UINT32 srowpixels, UINT32 swidth, UINT32 sheight, const render_color *color, UINT32 dx, UINT32 dy); static void resample_argb_bitmap_bilinear(UINT32 *dest, UINT32 drowpixels, UINT32 dwidth, UINT32 dheight, const UINT32 *source, UINT32 srowpixels, UINT32 swidth, UINT32 sheight, const render_color *color, UINT32 dx, UINT32 dy); -static void copy_png_to_bitmap(bitmap_t *bitmap, const png_info *png, int *hasalpha); -static void copy_png_alpha_to_bitmap(bitmap_t *bitmap, const png_info *png, int *hasalpha); +static void copy_png_to_bitmap(bitmap_t *bitmap, const png_info *png, bool *hasalpha); +static void copy_png_alpha_to_bitmap(bitmap_t *bitmap, const png_info *png, bool *hasalpha); @@ -560,7 +560,7 @@ void render_line_to_quad(const render_bounds *bounds, float width, render_bounds bitmap_t -------------------------------------------------*/ -bitmap_t *render_load_png(const char *path, const char *dirname, const char *filename, bitmap_t *alphadest, int *hasalpha) +bitmap_t *render_load_png(const char *path, const char *dirname, const char *filename, bitmap_t *alphadest, bool *hasalpha) { bitmap_t *bitmap = NULL; file_error filerr; @@ -636,7 +636,7 @@ bitmap_t *render_load_png(const char *path, const char *dirname, const char *fil bitmap -------------------------------------------------*/ -static void copy_png_to_bitmap(bitmap_t *bitmap, const png_info *png, int *hasalpha) +static void copy_png_to_bitmap(bitmap_t *bitmap, const png_info *png, bool *hasalpha) { UINT8 accumalpha = 0xff; UINT8 *src; @@ -701,7 +701,7 @@ static void copy_png_to_bitmap(bitmap_t *bitmap, const png_info *png, int *hasal to the alpha channel of a bitmap -------------------------------------------------*/ -static void copy_png_alpha_to_bitmap(bitmap_t *bitmap, const png_info *png, int *hasalpha) +static void copy_png_alpha_to_bitmap(bitmap_t *bitmap, const png_info *png, bool *hasalpha) { UINT8 accumalpha = 0xff; UINT8 *src; diff --git a/src/emu/rendutil.h b/src/emu/rendutil.h index 1331dd1282f..e6d1a423842 100644 --- a/src/emu/rendutil.h +++ b/src/emu/rendutil.h @@ -28,7 +28,7 @@ void render_resample_argb_bitmap_hq(void *dest, UINT32 drowpixels, UINT32 dwidth int render_clip_line(render_bounds *bounds, const render_bounds *clip); int render_clip_quad(render_bounds *bounds, const render_bounds *clip, render_quad_texuv *texcoords); void render_line_to_quad(const render_bounds *bounds, float width, render_bounds *bounds0, render_bounds *bounds1); -bitmap_t *render_load_png(const char *path, const char *dirname, const char *filename, bitmap_t *alphadest, int *hasalpha); +bitmap_t *render_load_png(const char *path, const char *dirname, const char *filename, bitmap_t *alphadest, bool *hasalpha); diff --git a/src/emu/video.c b/src/emu/video.c index 2ee3790864b..dbd52f117ee 100644 --- a/src/emu/video.c +++ b/src/emu/video.c @@ -312,7 +312,11 @@ void video_init(running_machine *machine) if (global.snap_native) { global.snap_target = machine->render().target_alloc(layout_snap, RENDER_CREATE_SINGLE_FILE | RENDER_CREATE_HIDDEN); - global.snap_target->set_layer_config(0); + global.snap_target->set_backdrops_enabled(false); + global.snap_target->set_overlays_enabled(false); + global.snap_target->set_bezels_enabled(false); + global.snap_target->set_screen_overlay_enabled(false); + global.snap_target->set_zoom_to_screen(false); } /* other targets select the specified view and turn off effects */ @@ -1603,13 +1607,19 @@ int video_get_view_for_target(running_machine *machine, render_target *target, c /* if we have enough targets to be one per screen, assign in order */ if (numtargets >= scrcount) { + int index = target->index() % scrcount; + screen_device *screen; + for (screen = screen_first(*machine); screen != NULL; screen = screen_next(screen)) + if (index-- == 0) + break; + /* find the first view with this screen and this screen only */ for (viewindex = 0; ; viewindex++) { - UINT32 viewscreens = target->view_screens(viewindex); - if (viewscreens == (1 << targetindex)) + const render_screen_list &viewscreens = target->view_screens(viewindex); + if (viewscreens.count() == 1 && viewscreens.contains(*screen)) break; - if (viewscreens == 0) + if (viewscreens.count() == 0) { viewindex = -1; break; @@ -1622,11 +1632,18 @@ int video_get_view_for_target(running_machine *machine, render_target *target, c { for (viewindex = 0; ; viewindex++) { - UINT32 viewscreens = target->view_screens(viewindex); - if (viewscreens == (1 << scrcount) - 1) - break; - if (viewscreens == 0) + const render_screen_list &viewscreens = target->view_screens(viewindex); + if (viewscreens.count() == 0) break; + if (viewscreens.count() >= scrcount) + { + screen_device *screen; + for (screen = screen_first(*machine); screen != NULL; screen = screen_next(screen)) + if (!viewscreens.contains(*screen)) + break; + if (screen == NULL) + break; + } } } } @@ -1942,9 +1959,6 @@ screen_device::~screen_device() void screen_device::device_start() { - // get and validate that the container for this screen exists - m_container = m_machine.render().container_for_screen(this); - // configure the default cliparea render_container::user_settings settings; m_container->get_user_settings(settings); diff --git a/src/emu/video.h b/src/emu/video.h index 3cd0d6142d8..8ffcc82537a 100644 --- a/src/emu/video.h +++ b/src/emu/video.h @@ -141,6 +141,7 @@ private: class screen_device : public device_t { friend class screen_device_config; + friend class render_manager; friend resource_pool_object::~resource_pool_object(); // construction/destruction @@ -199,6 +200,7 @@ private: virtual void device_post_load(); // internal helpers + void set_container(render_container &container) { m_container = &container; } void realloc_screen_bitmaps(); static TIMER_CALLBACK( static_vblank_begin_callback ) { reinterpret_cast(ptr)->vblank_begin_callback(); } diff --git a/src/osd/windows/video.h b/src/osd/windows/video.h index 98396188547..afb8ac65049 100644 --- a/src/osd/windows/video.h +++ b/src/osd/windows/video.h @@ -42,6 +42,8 @@ #ifndef __WIN_VIDEO__ #define __WIN_VIDEO__ +#include "render.h" + //============================================================ // CONSTANTS @@ -90,7 +92,7 @@ struct _win_video_config int prescale; // prescale factor int keepaspect; // keep aspect ratio int numscreens; // number of screens - int layerconfig; // default configuration of layers + render_layer_config layerconfig; // default configuration of layers // per-window configuration win_window_config window[MAX_WINDOWS]; // configuration data per-window diff --git a/src/osd/windows/window.c b/src/osd/windows/window.c index b9ee2aabf74..b8c82315822 100644 --- a/src/osd/windows/window.c +++ b/src/osd/windows/window.c @@ -718,7 +718,8 @@ static void winwindow_video_window_destroy(win_window_info *window) void winwindow_video_window_update(win_window_info *window) { - int targetview, targetorient, targetlayerconfig; + int targetview, targetorient; + render_layer_config targetlayerconfig; assert(GetCurrentThreadId() == main_threadid); diff --git a/src/osd/windows/window.h b/src/osd/windows/window.h index 7e743828bd3..64786a2ea75 100644 --- a/src/osd/windows/window.h +++ b/src/osd/windows/window.h @@ -100,7 +100,7 @@ struct _win_window_info render_target * target; int targetview; int targetorient; - int targetlayerconfig; + render_layer_config targetlayerconfig; render_primitive_list *primlist; // input info