diff options
| author | 2015-11-08 12:56:12 +0100 | |
|---|---|---|
| committer | 2015-11-08 12:56:12 +0100 | |
| commit | 7c19aac60e12d6f5ea301bdb34d7826a01e0b06f (patch) | |
| tree | f310d86aa2c6bfc19d115307dedde4eb0cd52dad /src/emu/render.c | |
| parent | a57b46ae933badd7441ce1644711dbb851e2b504 (diff) | |
Rename *.c -> *.cpp in our source (nw)
Diffstat (limited to 'src/emu/render.c')
| -rw-r--r-- | src/emu/render.c | 2801 |
1 files changed, 0 insertions, 2801 deletions
diff --git a/src/emu/render.c b/src/emu/render.c deleted file mode 100644 index 6ee9e871c43..00000000000 --- a/src/emu/render.c +++ /dev/null @@ -1,2801 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Aaron Giles -/*************************************************************************** - - render.c - - Core rendering system. - -**************************************************************************** - - Windows-specific to-do: - * no fallback if we run out of video memory - - Longer-term to do: (once old renderer is gone) - * make vector updates asynchronous - -**************************************************************************** - - Overview of objects: - - render_target -- This represents a final rendering target. It - is specified using integer width/height values, can have - non-square pixels, and you can specify its rotation. It is - what really determines the final rendering details. The OSD - layer creates one or more of these to encapsulate the - rendering process. Each render_target holds a list of - layout_files that it can use for drawing. When rendering, it - makes use of both layout_files and render_containers. - - render_container -- Containers are the top of a hierarchy that is - not directly related to the objects above. Containers hold - high level primitives that are generated at runtime by the - video system. They are used currently for each screen and - the user interface. These high-level primitives are broken down - into low-level primitives at render time. - -***************************************************************************/ - -#include "emu.h" -#include "emuopts.h" -#include "render.h" -#include "rendfont.h" -#include "rendlay.h" -#include "rendutil.h" -#include "config.h" -#include "drivenum.h" -#include "xmlfile.h" -#include "ui/ui.h" - - - -//************************************************************************** -// CONSTANTS -//************************************************************************** - -#define INTERNAL_FLAG_CHAR 0x00000001 - -enum -{ - COMPONENT_TYPE_IMAGE = 0, - COMPONENT_TYPE_RECT, - COMPONENT_TYPE_DISK, - COMPONENT_TYPE_MAX -}; - - -enum -{ - CONTAINER_ITEM_LINE = 0, - CONTAINER_ITEM_QUAD, - CONTAINER_ITEM_MAX -}; - - - -//************************************************************************** -// MACROS -//************************************************************************** - -#define ISWAP(var1, var2) do { int temp = var1; var1 = var2; var2 = temp; } while (0) -#define FSWAP(var1, var2) do { float temp = var1; var1 = var2; var2 = temp; } while (0) - - - -//************************************************************************** -// TYPE DEFINITIONS -//************************************************************************** - -// an object_transform is used to track transformations when building an object list -struct object_transform -{ - float xoffs, yoffs; // offset transforms - float xscale, yscale; // scale transforms - render_color color; // color transform - int orientation; // orientation transform - bool no_center; // center the container? -}; - - - -//************************************************************************** -// GLOBAL VARIABLES -//************************************************************************** - -// precomputed UV coordinates for various orientations -static const render_quad_texuv oriented_texcoords[8] = -{ - { { 0,0 }, { 1,0 }, { 0,1 }, { 1,1 } }, // 0 - { { 1,0 }, { 0,0 }, { 1,1 }, { 0,1 } }, // ORIENTATION_FLIP_X - { { 0,1 }, { 1,1 }, { 0,0 }, { 1,0 } }, // ORIENTATION_FLIP_Y - { { 1,1 }, { 0,1 }, { 1,0 }, { 0,0 } }, // ORIENTATION_FLIP_X | ORIENTATION_FLIP_Y - { { 0,0 }, { 0,1 }, { 1,0 }, { 1,1 } }, // ORIENTATION_SWAP_XY - { { 0,1 }, { 0,0 }, { 1,1 }, { 1,0 } }, // ORIENTATION_SWAP_XY | ORIENTATION_FLIP_X - { { 1,0 }, { 1,1 }, { 0,0 }, { 0,1 } }, // ORIENTATION_SWAP_XY | ORIENTATION_FLIP_Y - { { 1,1 }, { 1,0 }, { 0,1 }, { 0,0 } } // ORIENTATION_SWAP_XY | ORIENTATION_FLIP_X | ORIENTATION_FLIP_Y -}; - -// layer orders -static const int layer_order_standard[] = { ITEM_LAYER_SCREEN, ITEM_LAYER_OVERLAY, ITEM_LAYER_BACKDROP, ITEM_LAYER_BEZEL, ITEM_LAYER_CPANEL, ITEM_LAYER_MARQUEE }; -static const int layer_order_alternate[] = { ITEM_LAYER_BACKDROP, ITEM_LAYER_SCREEN, ITEM_LAYER_OVERLAY, ITEM_LAYER_BEZEL, ITEM_LAYER_CPANEL, ITEM_LAYER_MARQUEE }; - - - -//************************************************************************** -// INLINE FUNCTIONS -//************************************************************************** - -//------------------------------------------------- -// apply_orientation - apply orientation to a -// set of bounds -//------------------------------------------------- - -inline void apply_orientation(render_bounds &bounds, int orientation) -{ - // swap first - if (orientation & ORIENTATION_SWAP_XY) - { - FSWAP(bounds.x0, bounds.y0); - FSWAP(bounds.x1, bounds.y1); - } - - // apply X flip - if (orientation & ORIENTATION_FLIP_X) - { - bounds.x0 = 1.0f - bounds.x0; - bounds.x1 = 1.0f - bounds.x1; - } - - // apply Y flip - if (orientation & ORIENTATION_FLIP_Y) - { - bounds.y0 = 1.0f - bounds.y0; - bounds.y1 = 1.0f - bounds.y1; - } -} - - -//------------------------------------------------- -// normalize_bounds - normalize bounds so that -// x0/y0 are less than x1/y1 -//------------------------------------------------- - -inline void normalize_bounds(render_bounds &bounds) -{ - if (bounds.x0 > bounds.x1) - FSWAP(bounds.x0, bounds.x1); - if (bounds.y0 > bounds.y1) - FSWAP(bounds.y0, bounds.y1); -} - - -//------------------------------------------------- -// get_layer_and_blendmode - return the -// appropriate layer index and blendmode -//------------------------------------------------- - -inline item_layer get_layer_and_blendmode(const layout_view &view, int index, int &blendmode) -{ - // if we have multiple backdrop pieces and no overlays, render: - // backdrop (add) + screens (add) + bezels (alpha) + cpanels (alpha) + marquees (alpha) - // else render: - // screens (add) + overlays (RGB multiply) + backdrop (add) + bezels (alpha) + cpanels (alpha) + marquees (alpha) - - 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 - int layer = layer_order[index]; - - // pick a blendmode - if (layer == ITEM_LAYER_SCREEN && layer_order == layer_order_standard) - blendmode = -1; - else if (layer == ITEM_LAYER_SCREEN || (layer == ITEM_LAYER_BACKDROP && layer_order == layer_order_standard)) - blendmode = BLENDMODE_ADD; - else if (layer == ITEM_LAYER_OVERLAY) - blendmode = BLENDMODE_RGB_MULTIPLY; - else - blendmode = BLENDMODE_ALPHA; - - return item_layer(layer); -} - -//************************************************************************** -// RENDER PRIMITIVE -//************************************************************************** - -//------------------------------------------------- -// reset - reset the state of a primitive after -// it is re-allocated -//------------------------------------------------- - -void render_primitive::reset() -{ - // do not clear m_next! - memset(&type, 0, FPTR(&texcoords + 1) - FPTR(&type)); -} - - - -//************************************************************************** -// RENDER PRIMITIVE LIST -//************************************************************************** - -//------------------------------------------------- -// render_primitive_list - constructor -//------------------------------------------------- - -render_primitive_list::render_primitive_list() - : m_lock(osd_lock_alloc()) -{ -} - - -//------------------------------------------------- -// ~render_primitive_list - destructor -//------------------------------------------------- - -render_primitive_list::~render_primitive_list() -{ - release_all(); - osd_lock_free(m_lock); -} - - -//------------------------------------------------- -// add_reference - add a new reference -//------------------------------------------------- - -inline void render_primitive_list::add_reference(void *refptr) -{ - // skip if we already have one - if (has_reference(refptr)) - return; - - // set the refptr and link us into the list - reference *ref = m_reference_allocator.alloc(); - ref->m_refptr = refptr; - m_reflist.append(*ref); -} - - -//------------------------------------------------- -// has_reference - find a refptr in a reference -// list -//------------------------------------------------- - -inline bool render_primitive_list::has_reference(void *refptr) const -{ - // skip if we already have one - for (reference *ref = m_reflist.first(); ref != NULL; ref = ref->next()) - if (ref->m_refptr == refptr) - return true; - return false; -} - - -//------------------------------------------------- -// alloc - allocate a new empty primitive -//------------------------------------------------- - -inline render_primitive *render_primitive_list::alloc(render_primitive::primitive_type type) -{ - render_primitive *result = m_primitive_allocator.alloc(); - result->reset(); - result->type = type; - return result; -} - - -//------------------------------------------------- -// release_all - release the contents of -// a render list -//------------------------------------------------- - -void render_primitive_list::release_all() -{ - // release all the live items while under the lock - acquire_lock(); - m_primitive_allocator.reclaim_all(m_primlist); - m_reference_allocator.reclaim_all(m_reflist); - release_lock(); -} - - -//------------------------------------------------- -// append_or_return - append a primitive to the -// end of the list, or return it to the free -// list, based on a flag -//------------------------------------------------- - -void render_primitive_list::append_or_return(render_primitive &prim, bool clipped) -{ - if (!clipped) - m_primlist.append(prim); - else - m_primitive_allocator.reclaim(prim); -} - - - -//************************************************************************** -// RENDER TEXTURE -//************************************************************************** - -//------------------------------------------------- -// render_texture - constructor -//------------------------------------------------- - -render_texture::render_texture() - : m_manager(NULL), - m_next(NULL), - m_bitmap(NULL), - m_format(TEXFORMAT_ARGB32), - m_osddata(~0L), - m_scaler(NULL), - m_param(NULL), - m_curseq(0) -{ - m_sbounds.set(0, -1, 0, -1); - memset(m_scaled, 0, sizeof(m_scaled)); -} - - -//------------------------------------------------- -// ~render_texture - destructor -//------------------------------------------------- - -render_texture::~render_texture() -{ - release(); -} - - -//------------------------------------------------- -// reset - reset the state of a texture after -// it has been re-allocated -//------------------------------------------------- - -void render_texture::reset(render_manager &manager, texture_scaler_func scaler, void *param) -{ - m_manager = &manager; - if (scaler != NULL) - { - assert(m_format == TEXFORMAT_ARGB32); - m_scaler = scaler; - m_param = param; - } - m_osddata = ~0L; -} - - -//------------------------------------------------- -// release - release resources when we are freed -//------------------------------------------------- - -void render_texture::release() -{ - // free all scaled versions - for (int scalenum = 0; scalenum < ARRAY_LENGTH(m_scaled); scalenum++) - { - m_manager->invalidate_all(m_scaled[scalenum].bitmap); - global_free(m_scaled[scalenum].bitmap); - m_scaled[scalenum].bitmap = NULL; - m_scaled[scalenum].seqid = 0; - } - - // invalidate references to the original bitmap as well - m_manager->invalidate_all(m_bitmap); - m_bitmap = NULL; - m_sbounds.set(0, -1, 0, -1); - m_format = TEXFORMAT_ARGB32; - m_curseq = 0; -} - - -//------------------------------------------------- -// set_bitmap - set a new source bitmap -//------------------------------------------------- - -void render_texture::set_bitmap(bitmap_t &bitmap, const rectangle &sbounds, texture_format format) -{ - assert(bitmap.cliprect().contains(sbounds)); - - // ensure we have a valid palette for palettized modes - if (format == TEXFORMAT_PALETTE16 || format == TEXFORMAT_PALETTEA16) - assert(bitmap.palette() != NULL); - - // invalidate references to the old bitmap - if (&bitmap != m_bitmap && m_bitmap != NULL) - m_manager->invalidate_all(m_bitmap); - - // set the new bitmap/palette - m_bitmap = &bitmap; - m_sbounds = sbounds; - m_format = format; - - // invalidate all scaled versions - for (int scalenum = 0; scalenum < ARRAY_LENGTH(m_scaled); scalenum++) - { - if (m_scaled[scalenum].bitmap != NULL) - { - m_manager->invalidate_all(m_scaled[scalenum].bitmap); - global_free(m_scaled[scalenum].bitmap); - } - m_scaled[scalenum].bitmap = NULL; - m_scaled[scalenum].seqid = 0; - } -} - - -//------------------------------------------------- -// hq_scale - generic high quality resampling -// scaler -//------------------------------------------------- - -void render_texture::hq_scale(bitmap_argb32 &dest, bitmap_argb32 &source, const rectangle &sbounds, void *param) -{ - render_color color = { 1.0f, 1.0f, 1.0f, 1.0f }; - bitmap_argb32 sourcesub(source, sbounds); - render_resample_argb_bitmap_hq(dest, sourcesub, color); -} - - -//------------------------------------------------- -// get_scaled - get a scaled bitmap (if we can) -//------------------------------------------------- - -void render_texture::get_scaled(UINT32 dwidth, UINT32 dheight, render_texinfo &texinfo, render_primitive_list &primlist) -{ - // source width/height come from the source bounds - int swidth = m_sbounds.width(); - int sheight = m_sbounds.height(); - - // ensure height/width are non-zero - if (dwidth < 1) dwidth = 1; - if (dheight < 1) dheight = 1; - - texinfo.osddata = m_osddata; - - // are we scaler-free? if so, just return the source bitmap - if (m_scaler == NULL || (m_bitmap != NULL && swidth == dwidth && sheight == dheight)) - { - // add a reference and set up the source bitmap - primlist.add_reference(m_bitmap); - texinfo.base = m_bitmap->raw_pixptr(m_sbounds.min_y, m_sbounds.min_x); - texinfo.rowpixels = m_bitmap->rowpixels(); - texinfo.width = swidth; - texinfo.height = sheight; - // palette will be set later - texinfo.seqid = ++m_curseq; - } - else - { - // make sure we can recover the original argb32 bitmap - bitmap_argb32 dummy; - bitmap_argb32 &srcbitmap = (m_bitmap != NULL) ? downcast<bitmap_argb32 &>(*m_bitmap) : dummy; - - // is it a size we already have? - scaled_texture *scaled = NULL; - int scalenum; - for (scalenum = 0; scalenum < ARRAY_LENGTH(m_scaled); scalenum++) - { - scaled = &m_scaled[scalenum]; - - // we need a non-NULL bitmap with matching dest size - if (scaled->bitmap != NULL && dwidth == scaled->bitmap->width() && dheight == scaled->bitmap->height()) - break; - } - - // did we get one? - if (scalenum == ARRAY_LENGTH(m_scaled)) - { - int lowest = -1; - - // didn't find one -- take the entry with the lowest seqnum - for (scalenum = 0; scalenum < ARRAY_LENGTH(m_scaled); scalenum++) - if ((lowest == -1 || m_scaled[scalenum].seqid < m_scaled[lowest].seqid) && !primlist.has_reference(m_scaled[scalenum].bitmap)) - lowest = scalenum; - assert_always(lowest != -1, "Too many live texture instances!"); - - // throw out any existing entries - scaled = &m_scaled[lowest]; - if (scaled->bitmap != NULL) - { - m_manager->invalidate_all(scaled->bitmap); - global_free(scaled->bitmap); - } - - // allocate a new bitmap - scaled->bitmap = global_alloc(bitmap_argb32(dwidth, dheight)); - scaled->seqid = ++m_curseq; - - // let the scaler do the work - (*m_scaler)(*scaled->bitmap, srcbitmap, m_sbounds, m_param); - } - - // finally fill out the new info - primlist.add_reference(scaled->bitmap); - texinfo.base = &scaled->bitmap->pix32(0); - texinfo.rowpixels = scaled->bitmap->rowpixels(); - texinfo.width = dwidth; - texinfo.height = dheight; - // palette will be set later - texinfo.seqid = scaled->seqid; - } -} - - -//------------------------------------------------- -// get_adjusted_palette - return the adjusted -// palette for a texture -//------------------------------------------------- - -const rgb_t *render_texture::get_adjusted_palette(render_container &container) -{ - // override the palette with our adjusted palette - switch (m_format) - { - case TEXFORMAT_PALETTE16: - case TEXFORMAT_PALETTEA16: - - assert(m_bitmap->palette() != NULL); - - // return our adjusted palette - return container.bcg_lookup_table(m_format, m_bitmap->palette()); - - case TEXFORMAT_RGB32: - case TEXFORMAT_ARGB32: - case TEXFORMAT_YUY16: - - // if no adjustment necessary, return NULL - if (!container.has_brightness_contrast_gamma_changes()) - return NULL; - return container.bcg_lookup_table(m_format); - - default: - assert(FALSE); - } - - return NULL; -} - - - -//************************************************************************** -// RENDER CONTAINER -//************************************************************************** - -//------------------------------------------------- -// render_container - constructor -//------------------------------------------------- - -render_container::render_container(render_manager &manager, screen_device *screen) - : m_next(NULL), - m_manager(manager), - m_screen(screen), - m_overlaybitmap(NULL), - m_overlaytexture(NULL) -{ - // make sure it is empty - empty(); - - // if we have a screen, read and apply the options - if (m_screen != NULL) - { - // set the initial orientation and brightness/contrast/gamma - m_user.m_orientation = manager.machine().system().flags & ORIENTATION_MASK; - m_user.m_brightness = manager.machine().options().brightness(); - m_user.m_contrast = manager.machine().options().contrast(); - m_user.m_gamma = manager.machine().options().gamma(); - // palette client will be allocated later - } - - recompute_lookups(); -} - - -//------------------------------------------------- -// ~render_container - destructor -//------------------------------------------------- - -render_container::~render_container() -{ - // free all the container items - empty(); - - // free the overlay texture - m_manager.texture_free(m_overlaytexture); -} - - -//------------------------------------------------- -// set_overlay - set the overlay bitmap for the -// container -//------------------------------------------------- - -void render_container::set_overlay(bitmap_argb32 *bitmap) -{ - // free any existing texture - m_manager.texture_free(m_overlaytexture); - - // set the new data and allocate the texture - m_overlaybitmap = bitmap; - if (m_overlaybitmap != NULL) - { - m_overlaytexture = m_manager.texture_alloc(render_container::overlay_scale); - m_overlaytexture->set_bitmap(*bitmap, bitmap->cliprect(), TEXFORMAT_ARGB32); - } -} - - -//------------------------------------------------- -// set_user_settings - set the current user -// settings for a container -//------------------------------------------------- - -void render_container::set_user_settings(const user_settings &settings) -{ - m_user = settings; - recompute_lookups(); -} - - -//------------------------------------------------- -// add_line - add a line item to this container -//------------------------------------------------- - -void render_container::add_line(float x0, float y0, float x1, float y1, float width, rgb_t argb, UINT32 flags) -{ - item &newitem = add_generic(CONTAINER_ITEM_LINE, x0, y0, x1, y1, argb); - newitem.m_width = width; - newitem.m_flags = flags; -} - - -//------------------------------------------------- -// add_quad - add a quad item to this container -//------------------------------------------------- - -void render_container::add_quad(float x0, float y0, float x1, float y1, rgb_t argb, render_texture *texture, UINT32 flags) -{ - item &newitem = add_generic(CONTAINER_ITEM_QUAD, x0, y0, x1, y1, argb); - newitem.m_texture = texture; - newitem.m_flags = flags; -} - - -//------------------------------------------------- -// add_char - add a char item to this container -//------------------------------------------------- - -void render_container::add_char(float x0, float y0, float height, float aspect, rgb_t argb, render_font &font, UINT16 ch) -{ - // compute the bounds of the character cell and get the texture - render_bounds bounds; - bounds.x0 = x0; - bounds.y0 = y0; - render_texture *texture = font.get_char_texture_and_bounds(height, aspect, ch, bounds); - - // add it like a quad - item &newitem = add_generic(CONTAINER_ITEM_QUAD, bounds.x0, bounds.y0, bounds.x1, bounds.y1, argb); - newitem.m_texture = texture; - newitem.m_flags = PRIMFLAG_TEXORIENT(ROT0) | PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA); - newitem.m_internal = INTERNAL_FLAG_CHAR; -} - - -//------------------------------------------------- -// apply_brightness_contrast_gamma - apply the -// container's brightess, contrast, and gamma to -// an 8-bit value -//------------------------------------------------- - -UINT8 render_container::apply_brightness_contrast_gamma(UINT8 value) -{ - return ::apply_brightness_contrast_gamma(value, m_user.m_brightness, m_user.m_contrast, m_user.m_gamma); -} - - -//------------------------------------------------- -// apply_brightness_contrast_gamma_fp - apply the -// container's brightess, contrast, and gamma to -// a floating-point value -//------------------------------------------------- - -float render_container::apply_brightness_contrast_gamma_fp(float value) -{ - return ::apply_brightness_contrast_gamma_fp(value, m_user.m_brightness, m_user.m_contrast, m_user.m_gamma); -} - - -//------------------------------------------------- -// bcg_lookup_table - return the appropriate -// brightness/contrast/gamma lookup table for a -// given texture mode -//------------------------------------------------- - -const rgb_t *render_container::bcg_lookup_table(int texformat, palette_t *palette) -{ - switch (texformat) - { - case TEXFORMAT_PALETTE16: - case TEXFORMAT_PALETTEA16: - if (m_palclient == NULL) // if adjusted palette hasn't been created yet, create it - { - m_palclient.reset(global_alloc(palette_client(*palette))); - m_bcglookup.resize(palette->max_index()); - recompute_lookups(); - } - assert (palette == &m_palclient->palette()); - return &m_bcglookup[0]; - - case TEXFORMAT_RGB32: - case TEXFORMAT_ARGB32: - case TEXFORMAT_YUY16: - return m_bcglookup256; - - default: - return NULL; - } -} - - -//------------------------------------------------- -// overlay_scale - scaler for an overlay -//------------------------------------------------- - -void render_container::overlay_scale(bitmap_argb32 &dest, bitmap_argb32 &source, const rectangle &sbounds, void *param) -{ - // simply replicate the source bitmap over the target - for (int y = 0; y < dest.height(); y++) - { - UINT32 *src = &source.pix32(y % source.height()); - UINT32 *dst = &dest.pix32(y); - int sx = 0; - - // loop over columns - for (int x = 0; x < dest.width(); x++) - { - *dst++ = src[sx++]; - if (sx >= source.width()) - sx = 0; - } - } -} - - -//------------------------------------------------- -// add_generic - add a generic item to a -// container -//------------------------------------------------- - -render_container::item &render_container::add_generic(UINT8 type, float x0, float y0, float x1, float y1, rgb_t argb) -{ - item *newitem = m_item_allocator.alloc(); - - // copy the data into the new item - newitem->m_type = type; - newitem->m_bounds.x0 = x0; - newitem->m_bounds.y0 = y0; - newitem->m_bounds.x1 = x1; - newitem->m_bounds.y1 = y1; - newitem->m_color.r = (float)argb.r() * (1.0f / 255.0f); - newitem->m_color.g = (float)argb.g() * (1.0f / 255.0f); - newitem->m_color.b = (float)argb.b() * (1.0f / 255.0f); - newitem->m_color.a = (float)argb.a() * (1.0f / 255.0f); - newitem->m_flags = 0; - newitem->m_internal = 0; - newitem->m_width = 0; - newitem->m_texture = NULL; - - // add the item to the container - return m_itemlist.append(*newitem); -} - - -//------------------------------------------------- -// recompute_lookups - recompute the lookup table -// for the render container -//------------------------------------------------- - -void render_container::recompute_lookups() -{ - // recompute the 256 entry lookup table - for (int i = 0; i < 0x100; i++) - { - UINT8 adjustedval = apply_brightness_contrast_gamma(i); - m_bcglookup256[i + 0x000] = adjustedval << 0; - m_bcglookup256[i + 0x100] = adjustedval << 8; - m_bcglookup256[i + 0x200] = adjustedval << 16; - m_bcglookup256[i + 0x300] = adjustedval << 24; - } - - // recompute the palette entries - if (m_palclient != NULL) - { - palette_t &palette = m_palclient->palette(); - const rgb_t *adjusted_palette = palette.entry_list_adjusted(); - int colors = palette.max_index(); - - if (has_brightness_contrast_gamma_changes()) - { - for (int i = 0; i < colors; i++) - { - rgb_t newval = adjusted_palette[i]; - m_bcglookup[i] = (newval & 0xff000000) | - m_bcglookup256[0x200 + newval.r()] | - m_bcglookup256[0x100 + newval.g()] | - m_bcglookup256[0x000 + newval.b()]; - } - } - else - memcpy(&m_bcglookup[0], adjusted_palette, colors * sizeof(rgb_t)); - } -} - - -//------------------------------------------------- -// update_palette - update any dirty palette -// entries -//------------------------------------------------- - -void render_container::update_palette() -{ - // skip if no client - if (m_palclient == NULL) - return; - - // get the dirty list - UINT32 mindirty, maxdirty; - const UINT32 *dirty = m_palclient->dirty_list(mindirty, maxdirty); - - // iterate over dirty items and update them - if (dirty != NULL) - { - palette_t &palette = m_palclient->palette(); - const rgb_t *adjusted_palette = palette.entry_list_adjusted(); - - if (has_brightness_contrast_gamma_changes()) - { - // loop over chunks of 32 entries, since we can quickly examine 32 at a time - for (UINT32 entry32 = mindirty / 32; entry32 <= maxdirty / 32; entry32++) - { - UINT32 dirtybits = dirty[entry32]; - if (dirtybits != 0) - - // this chunk of 32 has dirty entries; fix them up - for (UINT32 entry = 0; entry < 32; entry++) - if (dirtybits & (1 << entry)) - { - UINT32 finalentry = entry32 * 32 + entry; - rgb_t newval = adjusted_palette[finalentry]; - m_bcglookup[finalentry] = (newval & 0xff000000) | - m_bcglookup256[0x200 + newval.r()] | - m_bcglookup256[0x100 + newval.g()] | - m_bcglookup256[0x000 + newval.b()]; - } - } - } - else - memcpy(&m_bcglookup[mindirty], &adjusted_palette[mindirty], (maxdirty - mindirty + 1) * sizeof(rgb_t)); - } -} - - -//------------------------------------------------- -// user_settings - constructor -//------------------------------------------------- - -render_container::user_settings::user_settings() - : m_orientation(0), - m_brightness(1.0f), - m_contrast(1.0f), - m_gamma(1.0f), - m_xscale(1.0f), - m_yscale(1.0f), - m_xoffset(0.0f), - m_yoffset(0.0f) -{ -} - - - -//************************************************************************** -// RENDER TARGET -//************************************************************************** - -//------------------------------------------------- -// render_target - constructor -//------------------------------------------------- - -render_target::render_target(render_manager &manager, const char *layoutfile, UINT32 flags) - : m_next(NULL), - m_manager(manager), - m_curview(NULL), - m_flags(flags), - m_listindex(0), - m_width(640), - m_height(480), - m_pixel_aspect(0.0f), - m_max_refresh(0), - m_orientation(0), - m_base_view(NULL), - m_base_orientation(ROT0), - m_maxtexwidth(65536), - m_maxtexheight(65536) -{ - // determine the base layer configuration based on options - m_base_layerconfig.set_backdrops_enabled(manager.machine().options().use_backdrops()); - m_base_layerconfig.set_overlays_enabled(manager.machine().options().use_overlays()); - m_base_layerconfig.set_bezels_enabled(manager.machine().options().use_bezels()); - m_base_layerconfig.set_cpanels_enabled(manager.machine().options().use_cpanels()); - m_base_layerconfig.set_marquees_enabled(manager.machine().options().use_marquees()); - m_base_layerconfig.set_zoom_to_screen(manager.machine().options().artwork_crop()); - - // determine the base orientation based on options - m_orientation = ROT0; - if (!manager.machine().options().rotate()) - m_base_orientation = orientation_reverse(manager.machine().system().flags & ORIENTATION_MASK); - - // rotate left/right - if (manager.machine().options().ror() || (manager.machine().options().auto_ror() && (manager.machine().system().flags & ORIENTATION_SWAP_XY))) - m_base_orientation = orientation_add(ROT90, m_base_orientation); - if (manager.machine().options().rol() || (manager.machine().options().auto_rol() && (manager.machine().system().flags & ORIENTATION_SWAP_XY))) - m_base_orientation = orientation_add(ROT270, m_base_orientation); - - // flip X/Y - if (manager.machine().options().flipx()) - m_base_orientation ^= ORIENTATION_FLIP_X; - if (manager.machine().options().flipy()) - m_base_orientation ^= ORIENTATION_FLIP_Y; - - // set the orientation and layerconfig equal to the base - m_orientation = m_base_orientation; - m_layerconfig = m_base_layerconfig; - - // load the layout files - load_layout_files(layoutfile, flags & RENDER_CREATE_SINGLE_FILE); - - // set the current view to the first one - set_view(0); - - // make us the UI target if there is none - if (!hidden() && manager.m_ui_target == NULL) - manager.set_ui_target(*this); -} - - -//------------------------------------------------- -// ~render_target - destructor -//------------------------------------------------- - -render_target::~render_target() -{ -} - - -//------------------------------------------------- -// is_ui_target - return true if this is the -// UI target -//------------------------------------------------- - -bool render_target::is_ui_target() const -{ - return (this == &m_manager.ui_target()); -} - - -//------------------------------------------------- -// index - return the index of this target -//------------------------------------------------- - -int render_target::index() const -{ - return m_manager.m_targetlist.indexof(*this); -} - - -//------------------------------------------------- -// set_bounds - set the bounds and pixel aspect -// of a target -//------------------------------------------------- - -void render_target::set_bounds(INT32 width, INT32 height, float pixel_aspect) -{ - m_width = width; - m_height = height; - m_bounds.x0 = m_bounds.y0 = 0; - m_bounds.x1 = (float)width; - m_bounds.y1 = (float)height; - m_pixel_aspect = pixel_aspect; -} - - -//------------------------------------------------- -// set_view - dynamically change the view for -// a target -//------------------------------------------------- - -void render_target::set_view(int viewindex) -{ - layout_view *view = view_by_index(viewindex); - if (view != NULL) - { - m_curview = view; - view->recompute(m_layerconfig); - } -} - - -//------------------------------------------------- -// set_max_texture_size - set the upper bound on -// the texture size -//------------------------------------------------- - -void render_target::set_max_texture_size(int maxwidth, int maxheight) -{ - m_maxtexwidth = maxwidth; - m_maxtexheight = maxheight; -} - - -//------------------------------------------------- -// configured_view - select a view for this -// target based on the configuration parameters -//------------------------------------------------- - -int render_target::configured_view(const char *viewname, int targetindex, int numtargets) -{ - layout_view *view = NULL; - int viewindex; - - // auto view just selects the nth view - if (strcmp(viewname, "auto") != 0) - { - // scan for a matching view name - for (view = view_by_index(viewindex = 0); view != NULL; view = view_by_index(++viewindex)) - if (core_strnicmp(view->name(), viewname, strlen(viewname)) == 0) - break; - } - - // if we don't have a match, default to the nth view - screen_device_iterator iter(m_manager.machine().root_device()); - int scrcount = iter.count(); - if (view == NULL && scrcount > 0) - { - // if we have enough targets to be one per screen, assign in order - if (numtargets >= scrcount) - { - int ourindex = index() % scrcount; - screen_device *screen = iter.byindex(ourindex); - - // find the first view with this screen and this screen only - for (view = view_by_index(viewindex = 0); view != NULL; view = view_by_index(++viewindex)) - { - const render_screen_list &viewscreens = view->screens(); - if (viewscreens.count() == 0) - { - view = NULL; - break; - } - else if (viewscreens.count() == viewscreens.contains(*screen)) - break; - } - } - - // otherwise, find the first view that has all the screens - if (view == NULL) - { - for (view = view_by_index(viewindex = 0); view != NULL; view = view_by_index(++viewindex)) - { - const render_screen_list &viewscreens = view->screens(); - if (viewscreens.count() == 0) - break; - if (viewscreens.count() >= scrcount) - { - screen_device *screen; - for (screen = iter.first(); screen != NULL; screen = iter.next()) - if (!viewscreens.contains(*screen)) - break; - if (screen == NULL) - break; - } - } - } - } - - // make sure it's a valid view - return (view != NULL) ? view_index(*view) : 0; -} - - -//------------------------------------------------- -// view_name - return the name of the given view -//------------------------------------------------- - -const char *render_target::view_name(int viewindex) -{ - layout_view *view = view_by_index(viewindex); - return (view != NULL) ? view->name() : NULL; -} - - -//------------------------------------------------- -// render_target_get_view_screens - return a -// bitmask of which screens are visible on a -// given view -//------------------------------------------------- - -const render_screen_list &render_target::view_screens(int viewindex) -{ - layout_view *view = view_by_index(viewindex); - return (view != NULL) ? view->screens() : s_empty_screen_list; -} - - -//------------------------------------------------- -// compute_visible_area - compute the visible -// area for the given target with the current -// layout and proposed new parameters -//------------------------------------------------- - -void render_target::compute_visible_area(INT32 target_width, INT32 target_height, float target_pixel_aspect, int target_orientation, INT32 &visible_width, INT32 &visible_height) -{ - float width, height; - float scale; - - // constrained case - if (target_pixel_aspect != 0.0f) - { - // start with the aspect ratio of the square pixel layout - width = m_curview->effective_aspect(m_layerconfig); - height = 1.0f; - - // first apply target orientation - if (target_orientation & ORIENTATION_SWAP_XY) - FSWAP(width, height); - - // apply the target pixel aspect ratio - height *= target_pixel_aspect; - - // based on the height/width ratio of the source and target, compute the scale factor - if (width / height > (float)target_width / (float)target_height) - scale = (float)target_width / width; - else - scale = (float)target_height / height; - } - - // stretch-to-fit case - else - { - width = (float)target_width; - height = (float)target_height; - scale = 1.0f; - } - - // set the final width/height - visible_width = render_round_nearest(width * scale); - visible_height = render_round_nearest(height * scale); -} - - -//------------------------------------------------- -// compute_minimum_size - compute the "minimum" -// size of a target, which is the smallest bounds -// that will ensure at least 1 target pixel per -// source pixel for all included screens -//------------------------------------------------- - -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().phase() == MACHINE_PHASE_EXIT) - { - minwidth = 640; - minheight = 480; - return; - } - - if (m_curview == NULL) - throw emu_fatalerror("Mandatory artwork is missing"); - - // scan the current view for all screens - for (item_layer layer = ITEM_LAYER_FIRST; layer < ITEM_LAYER_MAX; layer++) - - // iterate over items in the layer - for (layout_view::item *curitem = m_curview->first_item(layer); curitem != NULL; curitem = curitem->next()) - if (curitem->screen() != NULL) - { - // 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 = (screen->screen_type() == SCREEN_TYPE_VECTOR) ? vectorvis : screen->visible_area(); - - // apply target orientation to the 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 - float xscale, yscale; - if (!(orientation_add(m_orientation, screen->container().orientation()) & ORIENTATION_SWAP_XY)) - { - xscale = float(visarea.width()) / bounds.width(); - yscale = float(visarea.height()) / bounds.height(); - } - else - { - xscale = float(visarea.height()) / bounds.width(); - yscale = float(visarea.width()) / bounds.height(); - } - - // pick the greater - maxxscale = MAX(xscale, maxxscale); - maxyscale = MAX(yscale, maxyscale); - screens_considered++; - } - - // if there were no screens considered, pick a nominal default - if (screens_considered == 0) - { - maxxscale = 640.0f; - maxyscale = 480.0f; - } - - // round up - minwidth = render_round_nearest(maxxscale); - minheight = render_round_nearest(maxyscale); -} - - -//------------------------------------------------- -// get_primitives - return a list of primitives -// for a given render target -//------------------------------------------------- - -render_primitive_list &render_target::get_primitives() -{ - // remember the base values if this is the first frame - if (m_base_view == NULL) - m_base_view = m_curview; - - // switch to the next primitive list - render_primitive_list &list = m_primlist[m_listindex]; - m_listindex = (m_listindex + 1) % ARRAY_LENGTH(m_primlist); - list.acquire_lock(); - - // free any previous primitives - list.release_all(); - - // compute the visible width/height - INT32 viswidth, visheight; - compute_visible_area(m_width, m_height, m_pixel_aspect, m_orientation, viswidth, visheight); - - // create a root transform for the target - object_transform root_xform; - root_xform.xoffs = (float)(m_width - viswidth) / 2; - root_xform.yoffs = (float)(m_height - visheight) / 2; - root_xform.xscale = (float)viswidth; - root_xform.yscale = (float)visheight; - root_xform.color.r = root_xform.color.g = root_xform.color.b = root_xform.color.a = 1.0f; - root_xform.orientation = m_orientation; - root_xform.no_center = false; - - // iterate over layers back-to-front, but only if we're running - if (m_manager.machine().phase() >= MACHINE_PHASE_RESET) - for (item_layer layernum = ITEM_LAYER_FIRST; layernum < ITEM_LAYER_MAX; layernum++) - { - int blendmode; - item_layer layer = get_layer_and_blendmode(*m_curview, layernum, blendmode); - if (m_curview->layer_enabled(layer)) - { - // iterate over items in the layer - for (layout_view::item *curitem = m_curview->first_item(layer); curitem != NULL; curitem = curitem->next()) - { - // first apply orientation to the bounds - render_bounds bounds = curitem->bounds(); - apply_orientation(bounds, root_xform.orientation); - normalize_bounds(bounds); - - // apply the transform to the item - object_transform item_xform; - item_xform.xoffs = root_xform.xoffs + bounds.x0 * root_xform.xscale; - 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 = 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 (curitem->screen() != NULL) - add_container_primitives(list, item_xform, curitem->screen()->container(), blendmode); - else - add_element_primitives(list, item_xform, *curitem->element(), curitem->state(), blendmode); - } - } - } - - // if we are not in the running stage, draw an outer box - else - { - render_primitive *prim = list.alloc(render_primitive::QUAD); - set_render_bounds_xy(&prim->bounds, 0.0f, 0.0f, (float)m_width, (float)m_height); - set_render_color(&prim->color, 1.0f, 1.0f, 1.0f, 1.0f); - prim->texture.base = NULL; - prim->flags = PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA); - list.append(*prim); - - if (m_width > 1 && m_height > 1) - { - prim = list.alloc(render_primitive::QUAD); - set_render_bounds_xy(&prim->bounds, 1.0f, 1.0f, (float)(m_width - 1), (float)(m_height - 1)); - set_render_color(&prim->color, 1.0f, 0.0f, 0.0f, 0.0f); - prim->texture.base = NULL; - prim->flags = PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA); - list.append(*prim); - } - } - - // process the debug containers - for (render_container *debug = m_debug_containers.first(); debug != NULL; debug = debug->next()) - { - object_transform ui_xform; - ui_xform.xoffs = 0; - ui_xform.yoffs = 0; - ui_xform.xscale = (float)m_width; - ui_xform.yscale = (float)m_height; - ui_xform.color.r = ui_xform.color.g = ui_xform.color.b = ui_xform.color.a = 1.0f; - ui_xform.color.a = 0.9f; - ui_xform.orientation = m_orientation; - ui_xform.no_center = true; - - // add UI elements - add_container_primitives(list, ui_xform, *debug, BLENDMODE_ALPHA); - } - - // process the UI if we are the UI target - if (is_ui_target()) - { - // compute the transform for the UI - object_transform ui_xform; - ui_xform.xoffs = 0; - ui_xform.yoffs = 0; - ui_xform.xscale = (float) m_width; - ui_xform.yscale = (float) m_height; - ui_xform.color.r = ui_xform.color.g = ui_xform.color.b = ui_xform.color.a = 1.0f; - ui_xform.orientation = m_orientation; - ui_xform.no_center = false; - - // add UI elements - add_container_primitives(list, ui_xform, m_manager.ui_container(), BLENDMODE_ALPHA); - } - - // optimize the list before handing it off - add_clear_and_optimize_primitive_list(list); - list.release_lock(); - return list; -} - - -//------------------------------------------------- -// map_point_container - attempts to map a point -// on the specified render_target to the -// specified container, if possible -//------------------------------------------------- - -bool render_target::map_point_container(INT32 target_x, INT32 target_y, render_container &container, float &container_x, float &container_y) -{ - ioport_port *input_port; - ioport_value input_mask; - return map_point_internal(target_x, target_y, &container, container_x, container_y, input_port, input_mask); -} - - -//------------------------------------------------- -// map_point_input - attempts to map a point on -// the specified render_target to the specified -// container, if possible -//------------------------------------------------- - -bool render_target::map_point_input(INT32 target_x, INT32 target_y, ioport_port *&input_port, ioport_value &input_mask, float &input_x, float &input_y) -{ - return map_point_internal(target_x, target_y, NULL, input_x, input_y, input_port, input_mask);; -} - - -//------------------------------------------------- -// invalidate_all - if any of our primitive lists -// contain a reference to the given pointer, -// clear them -//------------------------------------------------- - -void render_target::invalidate_all(void *refptr) -{ - // iterate through all our primitive lists - for (int listnum = 0; listnum < ARRAY_LENGTH(m_primlist); listnum++) - { - render_primitive_list &list = m_primlist[listnum]; - - // if we have a reference to this object, release our list - list.acquire_lock(); - if (list.has_reference(refptr)) - list.release_all(); - list.release_lock(); - } -} - - -//------------------------------------------------- -// debug_alloc - allocate a container for a debug -// view -//------------------------------------------------- - -render_container *render_target::debug_alloc() -{ - return &m_debug_containers.append(*m_manager.container_alloc()); -} - - -//------------------------------------------------- -// debug_free - free a container for a debug view -//------------------------------------------------- - -void render_target::debug_free(render_container &container) -{ - m_debug_containers.remove(container); -} - - -//------------------------------------------------- -// debug_top - move a debug view container to -// the top of the list -//------------------------------------------------- - -void render_target::debug_top(render_container &container) -{ - m_debug_containers.prepend(m_debug_containers.detach(container)); -} - - -//------------------------------------------------- -// resolve_tags - resolve tag lookups -//------------------------------------------------- - -void render_target::resolve_tags() -{ - for (layout_file *file = m_filelist.first(); file != NULL; file = file->next()) - { - for (layout_view *view = file->first_view(); view != NULL; view = view->next()) - { - view->resolve_tags(); - } - } -} - - -//------------------------------------------------- -// 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 -//------------------------------------------------- - -void render_target::load_layout_files(const char *layoutfile, bool singlefile) -{ - bool have_default = false; - // if there's an explicit file, load that first - const char *basename = m_manager.machine().basename(); - if (layoutfile != NULL) - have_default |= load_layout_file(basename, layoutfile); - - // if we're only loading this file, we know our final result - if (singlefile) - return; - - // try to load a file based on the driver name - const game_driver &system = m_manager.machine().system(); - if (!load_layout_file(basename, system.name)) - have_default |= load_layout_file(basename, "default"); - else - have_default |= true; - - // if a default view has been specified, use that as a fallback - if (system.default_layout != NULL) - have_default |= load_layout_file(NULL, system.default_layout); - if (m_manager.machine().config().m_default_layout != NULL) - have_default |= load_layout_file(NULL, m_manager.machine().config().m_default_layout); - - // try to load another file based on the parent driver name - int cloneof = driver_list::clone(system); - if (cloneof != -1) { - if (!load_layout_file(driver_list::driver(cloneof).name, driver_list::driver(cloneof).name)) - have_default |= load_layout_file(driver_list::driver(cloneof).name, "default"); - else - have_default |= true; - } - screen_device_iterator iter(m_manager.machine().root_device()); - int screens = iter.count(); - // now do the built-in layouts for single-screen games - if (screens == 1) - { - if (system.flags & ORIENTATION_SWAP_XY) - load_layout_file(NULL, layout_vertical); - else - load_layout_file(NULL, layout_horizont); - assert_always(m_filelist.count() > 0, "Couldn't parse default layout??"); - } - if (!have_default) - { - if (screens == 0) - { - load_layout_file(NULL, layout_noscreens); - assert_always(m_filelist.count() > 0, "Couldn't parse default layout??"); - } - else - if (screens == 2) - { - load_layout_file(NULL, layout_dualhsxs); - assert_always(m_filelist.count() > 0, "Couldn't parse default layout??"); - } - else - if (screens == 3) - { - load_layout_file(NULL, layout_triphsxs); - assert_always(m_filelist.count() > 0, "Couldn't parse default layout??"); - } - else - if (screens == 4) - { - load_layout_file(NULL, layout_quadhsxs); - 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 - std::string fname = std::string(filename).append(".lay"); - if (dirname != NULL) - fname.insert(0, PATH_SEPARATOR).insert(0, dirname); - - // attempt to open the file; bail if we can't - emu_file layoutfile(manager().machine().options().art_path(), OPEN_FLAG_READ); - file_error filerr = layoutfile.open(fname.c_str()); - if (filerr != FILERR_NONE) - return false; - - // read the file - rootnode = xml_file_read(layoutfile, NULL); - } - - // if we didn't get a properly-formatted XML file, record a warning and exit - if (rootnode == NULL) - { - if (filename[0] != '<') - osd_printf_warning("Improperly formatted XML file '%s', ignoring\n", filename); - else - osd_printf_warning("Improperly formatted XML string, ignoring\n"); - return false; - } - - // parse and catch any errors - bool result = true; - try - { - m_filelist.append(*global_alloc(layout_file(m_manager.machine(), *rootnode, dirname))); - } - catch (emu_fatalerror &err) - { - if (filename[0] != '<') - osd_printf_warning("Error in XML file '%s': %s\n", filename, err.string()); - else - osd_printf_warning("Error in XML string: %s\n", err.string()); - result = false; - } - - // free the root node - xml_file_free(rootnode); - return result; -} - - -//------------------------------------------------- -// add_container_primitives - add primitives -// based on the container -//------------------------------------------------- - -void render_target::add_container_primitives(render_primitive_list &list, const object_transform &xform, render_container &container, int blendmode) -{ - // first update the palette for the container, if it is dirty - container.update_palette(); - - // compute the clip rect - render_bounds cliprect; - cliprect.x0 = xform.xoffs; - cliprect.y0 = xform.yoffs; - cliprect.x1 = xform.xoffs + xform.xscale; - cliprect.y1 = xform.yoffs + xform.yscale; - sect_render_bounds(&cliprect, &m_bounds); - - // compute the container transform - object_transform container_xform; - container_xform.orientation = orientation_add(container.orientation(), xform.orientation); - { - float xscale = (container_xform.orientation & ORIENTATION_SWAP_XY) ? container.yscale() : container.xscale(); - float yscale = (container_xform.orientation & ORIENTATION_SWAP_XY) ? container.xscale() : container.yscale(); - float xoffs = (container_xform.orientation & ORIENTATION_SWAP_XY) ? container.yoffset() : container.xoffset(); - float yoffs = (container_xform.orientation & ORIENTATION_SWAP_XY) ? container.xoffset() : container.yoffset(); - if (container_xform.orientation & ORIENTATION_FLIP_X) xoffs = -xoffs; - if (container_xform.orientation & ORIENTATION_FLIP_Y) yoffs = -yoffs; - container_xform.xscale = xform.xscale * xscale; - container_xform.yscale = xform.yscale * yscale; - if (xform.no_center) - { - container_xform.xoffs = xform.xscale * (xoffs) + xform.xoffs; - container_xform.yoffs = xform.yscale * (yoffs) + xform.yoffs; - } - else - { - container_xform.xoffs = xform.xscale * (0.5f - 0.5f * xscale + xoffs) + xform.xoffs; - container_xform.yoffs = xform.yscale * (0.5f - 0.5f * yscale + yoffs) + xform.yoffs; - } - container_xform.color = xform.color; - } - - // iterate over elements - for (render_container::item *curitem = container.first_item(); curitem != NULL; curitem = curitem->next()) - { - // compute the oriented bounds - render_bounds bounds = curitem->bounds(); - apply_orientation(bounds, container_xform.orientation); - - // allocate the primitive and set the transformed bounds/color data - render_primitive *prim = list.alloc(render_primitive::INVALID); - - prim->container = &container; /* pass the container along for access to user_settings */ - - prim->bounds.x0 = render_round_nearest(container_xform.xoffs + bounds.x0 * container_xform.xscale); - prim->bounds.y0 = render_round_nearest(container_xform.yoffs + bounds.y0 * container_xform.yscale); - if (curitem->internal() & INTERNAL_FLAG_CHAR) - { - prim->bounds.x1 = prim->bounds.x0 + render_round_nearest((bounds.x1 - bounds.x0) * container_xform.xscale); - prim->bounds.y1 = prim->bounds.y0 + render_round_nearest((bounds.y1 - bounds.y0) * container_xform.yscale); - } - else - { - prim->bounds.x1 = render_round_nearest(container_xform.xoffs + bounds.x1 * container_xform.xscale); - prim->bounds.y1 = render_round_nearest(container_xform.yoffs + bounds.y1 * container_xform.yscale); - } - - // compute the color of the primitive - prim->color.r = container_xform.color.r * curitem->color().r; - prim->color.g = container_xform.color.g * curitem->color().g; - prim->color.b = container_xform.color.b * curitem->color().b; - prim->color.a = container_xform.color.a * curitem->color().a; - - // now switch off the type - bool clipped = true; - switch (curitem->type()) - { - case CONTAINER_ITEM_LINE: - // adjust the color for brightness/contrast/gamma - prim->color.a = container.apply_brightness_contrast_gamma_fp(prim->color.a); - prim->color.r = container.apply_brightness_contrast_gamma_fp(prim->color.r); - prim->color.g = container.apply_brightness_contrast_gamma_fp(prim->color.g); - prim->color.b = container.apply_brightness_contrast_gamma_fp(prim->color.b); - - // set the line type - prim->type = render_primitive::LINE; - prim->flags |= PRIMFLAG_TYPE_LINE; - - // scale the width by the minimum of X/Y scale factors - prim->width = curitem->width() * MIN(container_xform.xscale, container_xform.yscale); - prim->flags |= curitem->flags(); - - // clip the primitive - clipped = render_clip_line(&prim->bounds, &cliprect); - break; - - case CONTAINER_ITEM_QUAD: - // set the quad type - prim->type = render_primitive::QUAD; - prim->flags |= PRIMFLAG_TYPE_QUAD; - - // normalize the bounds - normalize_bounds(prim->bounds); - - // get the scaled bitmap and set the resulting palette - if (curitem->texture() != NULL) - { - // determine the final orientation - int finalorient = orientation_add(PRIMFLAG_GET_TEXORIENT(curitem->flags()), container_xform.orientation); - - // based on the swap values, get the scaled final texture - int width = (finalorient & ORIENTATION_SWAP_XY) ? (prim->bounds.y1 - prim->bounds.y0) : (prim->bounds.x1 - prim->bounds.x0); - int height = (finalorient & ORIENTATION_SWAP_XY) ? (prim->bounds.x1 - prim->bounds.x0) : (prim->bounds.y1 - prim->bounds.y0); - width = MIN(width, m_maxtexwidth); - height = MIN(height, m_maxtexheight); - - curitem->texture()->get_scaled(width, height, prim->texture, list); - - // set the palette - prim->texture.palette = curitem->texture()->get_adjusted_palette(container); - - // determine UV coordinates and apply clipping - prim->texcoords = oriented_texcoords[finalorient]; - clipped = render_clip_quad(&prim->bounds, &cliprect, &prim->texcoords); - - // apply the final orientation from the quad flags and then build up the final flags - prim->flags = (curitem->flags() & ~(PRIMFLAG_TEXORIENT_MASK | PRIMFLAG_BLENDMODE_MASK | PRIMFLAG_TEXFORMAT_MASK)) | - PRIMFLAG_TEXORIENT(finalorient) | - PRIMFLAG_TEXFORMAT(curitem->texture()->format()); - if (blendmode != -1) - prim->flags |= PRIMFLAG_BLENDMODE(blendmode); - else - prim->flags |= PRIMFLAG_BLENDMODE(PRIMFLAG_GET_BLENDMODE(curitem->flags())); - } - else - { - // adjust the color for brightness/contrast/gamma - prim->color.r = container.apply_brightness_contrast_gamma_fp(prim->color.r); - prim->color.g = container.apply_brightness_contrast_gamma_fp(prim->color.g); - prim->color.b = container.apply_brightness_contrast_gamma_fp(prim->color.b); - - // no texture -- set the basic flags - prim->texture.base = NULL; - prim->flags = (curitem->flags() &~ PRIMFLAG_BLENDMODE_MASK) | PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA); - - // apply clipping - clipped = render_clip_quad(&prim->bounds, &cliprect, NULL); - } - break; - } - - // add to the list or free if we're clipped out - list.append_or_return(*prim, clipped); - } - - // add the overlay if it exists - if (container.overlay() != NULL && m_layerconfig.screen_overlay_enabled()) - { - INT32 width, height; - - // allocate a primitive - render_primitive *prim = list.alloc(render_primitive::QUAD); - set_render_bounds_wh(&prim->bounds, xform.xoffs, xform.yoffs, xform.xscale, xform.yscale); - prim->color = container_xform.color; - width = render_round_nearest(prim->bounds.x1) - render_round_nearest(prim->bounds.x0); - height = render_round_nearest(prim->bounds.y1) - render_round_nearest(prim->bounds.y0); - - container.overlay()->get_scaled( - (container_xform.orientation & ORIENTATION_SWAP_XY) ? height : width, - (container_xform.orientation & ORIENTATION_SWAP_XY) ? width : height, prim->texture, list); - - // determine UV coordinates - prim->texcoords = oriented_texcoords[container_xform.orientation]; - - // set the flags and add it to the list - prim->flags = PRIMFLAG_TEXORIENT(container_xform.orientation) | - PRIMFLAG_BLENDMODE(BLENDMODE_RGB_MULTIPLY) | - PRIMFLAG_TEXFORMAT(container.overlay()->format()) | - PRIMFLAG_TEXSHADE(1); - - list.append_or_return(*prim, false); - } -} - - -//------------------------------------------------- -// add_element_primitives - add the primitive -// for an element in the current state -//------------------------------------------------- - -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()) - return; - if (state < 0) - state = 0; - - // get a pointer to the relevant texture - render_texture *texture = element.state_texture(state); - if (texture != NULL) - { - render_primitive *prim = list.alloc(render_primitive::QUAD); - - // configure the basics - prim->color = xform.color; - prim->flags = PRIMFLAG_TEXORIENT(xform.orientation) | PRIMFLAG_BLENDMODE(blendmode) | PRIMFLAG_TEXFORMAT(texture->format()); - - // compute the bounds - INT32 width = render_round_nearest(xform.xscale); - INT32 height = render_round_nearest(xform.yscale); - set_render_bounds_wh(&prim->bounds, render_round_nearest(xform.xoffs), render_round_nearest(xform.yoffs), (float) width, (float) height); - if (xform.orientation & ORIENTATION_SWAP_XY) - ISWAP(width, height); - width = MIN(width, m_maxtexwidth); - height = MIN(height, m_maxtexheight); - - // get the scaled texture and append it - - texture->get_scaled(width, height, prim->texture, list); - - // compute the clip rect - render_bounds cliprect; - cliprect.x0 = render_round_nearest(xform.xoffs); - cliprect.y0 = render_round_nearest(xform.yoffs); - cliprect.x1 = render_round_nearest(xform.xoffs + xform.xscale); - cliprect.y1 = render_round_nearest(xform.yoffs + xform.yscale); - sect_render_bounds(&cliprect, &m_bounds); - - // determine UV coordinates and apply clipping - prim->texcoords = oriented_texcoords[xform.orientation]; - bool clipped = render_clip_quad(&prim->bounds, &cliprect, &prim->texcoords); - - // add to the list or free if we're clipped out - list.append_or_return(*prim, clipped); - } -} - - -//------------------------------------------------- -// map_point_internal - internal logic for -// mapping points -//------------------------------------------------- - -bool render_target::map_point_internal(INT32 target_x, INT32 target_y, render_container *container, float &mapped_x, float &mapped_y, ioport_port *&mapped_input_port, ioport_value &mapped_input_mask) -{ - // compute the visible width/height - INT32 viswidth, visheight; - compute_visible_area(m_width, m_height, m_pixel_aspect, m_orientation, viswidth, visheight); - - // create a root transform for the target - object_transform root_xform; - root_xform.xoffs = (float)(m_width - viswidth) / 2; - root_xform.yoffs = (float)(m_height - visheight) / 2; - - // default to point not mapped - mapped_x = -1.0; - mapped_y = -1.0; - mapped_input_port = NULL; - mapped_input_mask = 0; - - // convert target coordinates to float - float target_fx = (float)(target_x - root_xform.xoffs) / viswidth; - float target_fy = (float)(target_y - root_xform.yoffs) / visheight; - if (manager().machine().ui().is_menu_active()) - { - target_fx = (float)target_x / m_width; - target_fy = (float)target_y / m_height; - } - // explicitly check for the UI container - if (container != NULL && container == &m_manager.ui_container()) - { - // this hit test went against the UI container - if (target_fx >= 0.0f && target_fx < 1.0f && target_fy >= 0.0f && target_fy < 1.0f) - { - // this point was successfully mapped - mapped_x = (float)target_x / m_width; - mapped_y = (float)target_y / m_height; - return true; - } - return false; - } - - // loop through each layer - for (item_layer layernum = ITEM_LAYER_FIRST; layernum < ITEM_LAYER_MAX; layernum++) - { - int blendmode; - item_layer layer = get_layer_and_blendmode(*m_curview, layernum, blendmode); - if (m_curview->layer_enabled(layer)) - { - // iterate over items in the layer - 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->screen() != NULL && &item->screen()->container() == container); - - // otherwise, assume we're looking for an input - else - 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) - { - // 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_input_port = item->input_tag_and_mask(mapped_input_mask); - return true; - } - } - } - } - return false; -} - - -//------------------------------------------------- -// view_name - return the name of the indexed -// view, or NULL if it doesn't exist -//------------------------------------------------- - -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.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; -} - - -//------------------------------------------------- -// view_index - return the index of the given -// view -//------------------------------------------------- - -int render_target::view_index(layout_view &targetview) const -{ - // find the first named match - int index = 0; - - // scan the list of views within each layout, skipping those that don't apply - 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; - index++; - } - return 0; -} - - -//------------------------------------------------- -// config_load - process config information -//------------------------------------------------- - -void render_target::config_load(xml_data_node &targetnode) -{ - // find the view - const char *viewname = xml_get_attribute_string(&targetnode, "view", NULL); - if (viewname != NULL) - for (int viewnum = 0; viewnum < 1000; viewnum++) - { - const char *testname = view_name(viewnum); - if (testname == NULL) - break; - if (!strcmp(viewname, testname)) - { - set_view(viewnum); - break; - } - } - - // modify the artwork config - int tmpint = xml_get_attribute_int(&targetnode, "backdrops", -1); - if (tmpint == 0 || tmpint == 1) - set_backdrops_enabled(tmpint); - - tmpint = xml_get_attribute_int(&targetnode, "overlays", -1); - if (tmpint == 0 || tmpint == 1) - set_overlays_enabled(tmpint); - - tmpint = xml_get_attribute_int(&targetnode, "bezels", -1); - if (tmpint == 0 || tmpint == 1) - set_bezels_enabled(tmpint); - - tmpint = xml_get_attribute_int(&targetnode, "cpanels", -1); - if (tmpint == 0 || tmpint == 1) - set_cpanels_enabled(tmpint); - - tmpint = xml_get_attribute_int(&targetnode, "marquees", -1); - if (tmpint == 0 || tmpint == 1) - set_marquees_enabled(tmpint); - - tmpint = xml_get_attribute_int(&targetnode, "zoom", -1); - if (tmpint == 0 || tmpint == 1) - set_zoom_to_screen(tmpint); - - // apply orientation - tmpint = xml_get_attribute_int(&targetnode, "rotate", -1); - if (tmpint != -1) - { - if (tmpint == 90) - tmpint = ROT90; - else if (tmpint == 180) - tmpint = ROT180; - else if (tmpint == 270) - tmpint = ROT270; - else - tmpint = ROT0; - set_orientation(orientation_add(tmpint, orientation())); - - // apply the opposite orientation to the UI - if (is_ui_target()) - { - render_container::user_settings settings; - render_container &ui_container = m_manager.ui_container(); - - ui_container.get_user_settings(settings); - settings.m_orientation = orientation_add(orientation_reverse(tmpint), settings.m_orientation); - ui_container.set_user_settings(settings); - } - } -} - - -//------------------------------------------------- -// config_save - save our configuration, or -// return false if we are the same as the default -//------------------------------------------------- - -bool render_target::config_save(xml_data_node &targetnode) -{ - bool changed = false; - - // output the basics - xml_set_attribute_int(&targetnode, "index", index()); - - // output the view - if (m_curview != m_base_view) - { - 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", 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, "cpanels", m_layerconfig.cpanels_enabled()); - xml_set_attribute_int(&targetnode, "marquees", m_layerconfig.marquees_enabled()); - xml_set_attribute_int(&targetnode, "zoom", m_layerconfig.zoom_to_screen()); - changed = true; - } - - // output rotation - if (m_orientation != m_base_orientation) - { - int rotate = 0; - if (orientation_add(ROT90, m_base_orientation) == m_orientation) - rotate = 90; - else if (orientation_add(ROT180, m_base_orientation) == m_orientation) - rotate = 180; - else if (orientation_add(ROT270, m_base_orientation) == m_orientation) - rotate = 270; - assert(rotate != 0); - xml_set_attribute_int(&targetnode, "rotate", rotate); - changed = true; - } - - return changed; -} - - -//------------------------------------------------- -// init_clear_extents - reset the extents list -//------------------------------------------------- - -void render_target::init_clear_extents() -{ - m_clear_extents[0] = -m_height; - m_clear_extents[1] = 1; - m_clear_extents[2] = m_width; - m_clear_extent_count = 3; -} - - -//------------------------------------------------- -// remove_clear_extent - remove a quad from the -// list of stuff to clear, unless it overlaps -// a previous quad -//------------------------------------------------- - -bool render_target::remove_clear_extent(const render_bounds &bounds) -{ - INT32 *max = &m_clear_extents[MAX_CLEAR_EXTENTS]; - INT32 *last = &m_clear_extents[m_clear_extent_count]; - INT32 *ext = &m_clear_extents[0]; - INT32 boundsx0 = ceil(bounds.x0); - INT32 boundsx1 = floor(bounds.x1); - INT32 boundsy0 = ceil(bounds.y0); - INT32 boundsy1 = floor(bounds.y1); - INT32 y0, y1 = 0; - - // loop over Y extents - while (ext < last) - { - INT32 *linelast; - - // first entry of each line should always be negative - assert(ext[0] < 0.0f); - y0 = y1; - y1 = y0 - ext[0]; - - // do we intersect this extent? - if (boundsy0 < y1 && boundsy1 > y0) - { - INT32 *xext; - INT32 x0, x1 = 0; - - // split the top - if (y0 < boundsy0) - { - int diff = boundsy0 - y0; - - // make a copy of this extent - memmove(&ext[ext[1] + 2], &ext[0], (last - ext) * sizeof(*ext)); - last += ext[1] + 2; - assert_always(last < max, "Ran out of clear extents!\n"); - - // split the extent between pieces - ext[ext[1] + 2] = -(-ext[0] - diff); - ext[0] = -diff; - - // advance to the new extent - y0 -= ext[0]; - ext += ext[1] + 2; - y1 = y0 - ext[0]; - } - - // split the bottom - if (y1 > boundsy1) - { - int diff = y1 - boundsy1; - - // make a copy of this extent - memmove(&ext[ext[1] + 2], &ext[0], (last - ext) * sizeof(*ext)); - last += ext[1] + 2; - assert_always(last < max, "Ran out of clear extents!\n"); - - // split the extent between pieces - ext[ext[1] + 2] = -diff; - ext[0] = -(-ext[0] - diff); - - // recompute y1 - y1 = y0 - ext[0]; - } - - // now remove the X extent - linelast = &ext[ext[1] + 2]; - xext = &ext[2]; - while (xext < linelast) - { - x0 = x1; - x1 = x0 + xext[0]; - - // do we fully intersect this extent? - if (boundsx0 >= x0 && boundsx1 <= x1) - { - // yes; split it - memmove(&xext[2], &xext[0], (last - xext) * sizeof(*xext)); - last += 2; - linelast += 2; - assert_always(last < max, "Ran out of clear extents!\n"); - - // split this extent into three parts - xext[0] = boundsx0 - x0; - xext[1] = boundsx1 - boundsx0; - xext[2] = x1 - boundsx1; - - // recompute x1 - x1 = boundsx1; - xext += 2; - } - - // do we partially intersect this extent? - else if (boundsx0 < x1 && boundsx1 > x0) - goto abort; - - // advance - xext++; - - // do we partially intersect the next extent (which is a non-clear extent)? - if (xext < linelast) - { - x0 = x1; - x1 = x0 + xext[0]; - if (boundsx0 < x1 && boundsx1 > x0) - goto abort; - xext++; - } - } - - // update the count - ext[1] = linelast - &ext[2]; - } - - // advance to the next row - ext += 2 + ext[1]; - } - - // update the total count - m_clear_extent_count = last - &m_clear_extents[0]; - return true; - -abort: - // update the total count even on a failure as we may have split extents - m_clear_extent_count = last - &m_clear_extents[0]; - return false; -} - - -//------------------------------------------------- -// add_clear_extents - add the accumulated -// extents as a series of quads to clear -//------------------------------------------------- - -void render_target::add_clear_extents(render_primitive_list &list) -{ - simple_list<render_primitive> clearlist; - INT32 *last = &m_clear_extents[m_clear_extent_count]; - INT32 *ext = &m_clear_extents[0]; - INT32 y0, y1 = 0; - - // loop over all extents - while (ext < last) - { - INT32 *linelast = &ext[ext[1] + 2]; - INT32 *xext = &ext[2]; - INT32 x0, x1 = 0; - - // first entry should always be negative - assert(ext[0] < 0); - y0 = y1; - y1 = y0 - ext[0]; - - // now remove the X extent - while (xext < linelast) - { - x0 = x1; - x1 = x0 + *xext++; - - // only add entries for non-zero widths - if (x1 - x0 > 0) - { - render_primitive *prim = list.alloc(render_primitive::QUAD); - set_render_bounds_xy(&prim->bounds, (float)x0, (float)y0, (float)x1, (float)y1); - set_render_color(&prim->color, 1.0f, 0.0f, 0.0f, 0.0f); - prim->texture.base = NULL; - prim->flags = PRIMFLAG_BLENDMODE(BLENDMODE_ALPHA); - clearlist.append(*prim); - } - - // skip the non-clearing extent - x0 = x1; - x1 = x0 + *xext++; - } - - // advance to the next part - ext += 2 + ext[1]; - } - - // we know that the first primitive in the list will be the global clip - // so we insert the clears immediately after - list.m_primlist.prepend_list(clearlist); -} - - -//------------------------------------------------- -// add_clear_and_optimize_primitive_list - -// optimize the primitive list -//------------------------------------------------- - -void render_target::add_clear_and_optimize_primitive_list(render_primitive_list &list) -{ - // start with the assumption that we need to clear the whole screen - init_clear_extents(); - - // scan the list until we hit an intersection quad or a line - for (render_primitive *prim = list.first(); prim != NULL; prim = prim->next()) - { - // switch off the type - switch (prim->type) - { - case render_primitive::LINE: - goto done; - - case render_primitive::QUAD: - { - // stop when we hit an alpha texture - if (PRIMFLAG_GET_TEXFORMAT(prim->flags) == TEXFORMAT_ARGB32 || PRIMFLAG_GET_TEXFORMAT(prim->flags) == TEXFORMAT_PALETTEA16) - goto done; - - // if this quad can't be cleanly removed from the extents list, we're done - if (!remove_clear_extent(prim->bounds)) - goto done; - - // change the blendmode on the first primitive to be NONE - if (PRIMFLAG_GET_BLENDMODE(prim->flags) == BLENDMODE_RGB_MULTIPLY) - { - // RGB multiply will multiply against 0, leaving nothing - set_render_color(&prim->color, 1.0f, 0.0f, 0.0f, 0.0f); - prim->texture.base = NULL; - prim->flags = (prim->flags & ~PRIMFLAG_BLENDMODE_MASK) | PRIMFLAG_BLENDMODE(BLENDMODE_NONE); - } - else - { - // for alpha or add modes, we will blend against 0 or add to 0; treat it like none - prim->flags = (prim->flags & ~PRIMFLAG_BLENDMODE_MASK) | PRIMFLAG_BLENDMODE(BLENDMODE_NONE); - } - - // since alpha is disabled, premultiply the RGB values and reset the alpha to 1.0 - prim->color.r *= prim->color.a; - prim->color.g *= prim->color.a; - prim->color.b *= prim->color.a; - prim->color.a = 1.0f; - break; - } - - default: - throw emu_fatalerror("Unexpected primitive type"); - } - } - -done: - // now add the extents to the clear list - add_clear_extents(list); -} - - - -//************************************************************************** -// CORE IMPLEMENTATION -//************************************************************************** - -//------------------------------------------------- -// render_manager - constructor -//------------------------------------------------- - -render_manager::render_manager(running_machine &machine) - : m_machine(machine), - m_ui_target(NULL), - m_live_textures(0), - m_ui_container(global_alloc(render_container(*this))) -{ - // register callbacks - config_register(machine, "video", config_saveload_delegate(FUNC(render_manager::config_load), this), config_saveload_delegate(FUNC(render_manager::config_save), this)); - - // create one container per screen - screen_device_iterator iter(machine.root_device()); - for (screen_device *screen = iter.first(); screen != NULL; screen = iter.next()) - screen->set_container(*container_alloc(screen)); -} - - -//------------------------------------------------- -// ~render_manager - destructor -//------------------------------------------------- - -render_manager::~render_manager() -{ - // free all the containers since they may own textures - container_free(m_ui_container); - m_screen_container_list.reset(); - - // better not be any outstanding textures when we die - assert(m_live_textures == 0); -} - - -//------------------------------------------------- -// is_live - return if the screen is 'live' -//------------------------------------------------- - -bool render_manager::is_live(screen_device &screen) const -{ - // iterate over all live targets and or together their screen masks - for (render_target *target = m_targetlist.first(); target != NULL; target = target->next()) - if (!target->hidden() && target->view_screens(target->view()).contains(screen)) - return true; - return false; -} - - -//------------------------------------------------- -// max_update_rate - return the smallest maximum -// update rate across all targets -//------------------------------------------------- - -float render_manager::max_update_rate() const -{ - // iterate over all live targets and or together their screen masks - float minimum = 0; - for (render_target *target = m_targetlist.first(); target != NULL; target = target->next()) - if (target->max_update_rate() != 0) - { - if (minimum == 0) - minimum = target->max_update_rate(); - else - minimum = MIN(target->max_update_rate(), minimum); - } - - return minimum; -} - - -//------------------------------------------------- -// target_alloc - allocate a new target -//------------------------------------------------- - -render_target *render_manager::target_alloc(const char *layoutfile, UINT32 flags) -{ - return &m_targetlist.append(*global_alloc(render_target(*this, layoutfile, flags))); -} - - -//------------------------------------------------- -// target_free - free a target -//------------------------------------------------- - -void render_manager::target_free(render_target *target) -{ - if (target != NULL) - m_targetlist.remove(*target); -} - - -//------------------------------------------------- -// target_by_index - get a render_target by index -//------------------------------------------------- - -render_target *render_manager::target_by_index(int index) const -{ - // count up the targets until we hit the requested index - for (render_target *target = m_targetlist.first(); target != NULL; target = target->next()) - if (!target->hidden()) - if (index-- == 0) - return target; - return NULL; -} - - -//------------------------------------------------- -// ui_aspect - return the aspect ratio for UI -// fonts -//------------------------------------------------- - -float render_manager::ui_aspect(render_container *rc) -{ - int orient = 0; - float aspect = 1.0f; - - if (rc == m_ui_container || rc == NULL) { - // ui container, aggregated multi-screen target - - orient = orientation_add(m_ui_target->orientation(), m_ui_container->orientation()); - // based on the orientation of the target, compute height/width or width/height - if (!(orient & ORIENTATION_SWAP_XY)) - aspect = (float)m_ui_target->height() / (float)m_ui_target->width(); - else - aspect = (float)m_ui_target->width() / (float)m_ui_target->height(); - - // if we have a valid pixel aspect, apply that and return - if (m_ui_target->pixel_aspect() != 0.0f) - return (aspect / m_ui_target->pixel_aspect()); - } else { - // single screen container - - orient = rc->orientation(); - // based on the orientation of the target, compute height/width or width/height - if (!(orient & ORIENTATION_SWAP_XY)) - aspect = (float)rc->screen()->visible_area().height() / (float)rc->screen()->visible_area().width(); - else - aspect = (float)rc->screen()->visible_area().width() / (float)rc->screen()->visible_area().height(); - } - - // clamp for extreme proportions - if (aspect < 0.66f) - aspect = 0.66f; - if (aspect > 1.5f) - aspect = 1.5f; - - return aspect; -} - - -//------------------------------------------------- -// texture_alloc - allocate a new texture -//------------------------------------------------- - -render_texture *render_manager::texture_alloc(texture_scaler_func scaler, void *param) -{ - // allocate a new texture and reset it - render_texture *tex = m_texture_allocator.alloc(); - tex->reset(*this, scaler, param); - m_live_textures++; - return tex; -} - - -//------------------------------------------------- -// texture_free - release a texture -//------------------------------------------------- - -void render_manager::texture_free(render_texture *texture) -{ - if (texture != NULL) - { - m_live_textures--; - texture->release(); - } - m_texture_allocator.reclaim(texture); -} - - -//------------------------------------------------- -// font_alloc - allocate a new font instance -//------------------------------------------------- - -render_font *render_manager::font_alloc(const char *filename) -{ - return global_alloc(render_font(*this, filename)); -} - - -//------------------------------------------------- -// font_free - release a font instance -//------------------------------------------------- - -void render_manager::font_free(render_font *font) -{ - global_free(font); -} - - -//------------------------------------------------- -// invalidate_all - remove all refs to a -// particular reference pointer -//------------------------------------------------- - -void render_manager::invalidate_all(void *refptr) -{ - // permit NULL - if (refptr == NULL) - return; - - // loop over targets - for (render_target *target = m_targetlist.first(); target != NULL; target = target->next()) - target->invalidate_all(refptr); -} - - -//------------------------------------------------- -// resolve_tags - resolve tag lookups -//------------------------------------------------- - -void render_manager::resolve_tags() -{ - for (render_target *target = m_targetlist.first(); target != NULL; target = target->next()) - { - target->resolve_tags(); - } -} - - -//------------------------------------------------- -// container_alloc - allocate a new container -//------------------------------------------------- - -render_container *render_manager::container_alloc(screen_device *screen) -{ - render_container *container = global_alloc(render_container(*this, screen)); - if (screen != NULL) - m_screen_container_list.append(*container); - return container; -} - - -//------------------------------------------------- -// container_free - release a container -//------------------------------------------------- - -void render_manager::container_free(render_container *container) -{ - m_screen_container_list.remove(*container); -} - - -//------------------------------------------------- -// config_load - read and apply data from the -// configuration file -//------------------------------------------------- - -void render_manager::config_load(int config_type, xml_data_node *parentnode) -{ - // we only care about game files - if (config_type != CONFIG_TYPE_GAME) - return; - - // might not have any data - if (parentnode == NULL) - return; - - // check the UI target - xml_data_node *uinode = xml_get_sibling(parentnode->child, "interface"); - if (uinode != NULL) - { - render_target *target = target_by_index(xml_get_attribute_int(uinode, "target", 0)); - if (target != NULL) - set_ui_target(*target); - } - - // iterate over target nodes - for (xml_data_node *targetnode = xml_get_sibling(parentnode->child, "target"); targetnode; targetnode = xml_get_sibling(targetnode->next, "target")) - { - render_target *target = target_by_index(xml_get_attribute_int(targetnode, "index", -1)); - if (target != NULL) - target->config_load(*targetnode); - } - - // iterate over screen nodes - for (xml_data_node *screennode = xml_get_sibling(parentnode->child, "screen"); screennode; screennode = xml_get_sibling(screennode->next, "screen")) - { - int index = xml_get_attribute_int(screennode, "index", -1); - render_container *container = m_screen_container_list.find(index); - render_container::user_settings settings; - - // fetch current settings - container->get_user_settings(settings); - - // fetch color controls - settings.m_brightness = xml_get_attribute_float(screennode, "brightness", settings.m_brightness); - settings.m_contrast = xml_get_attribute_float(screennode, "contrast", settings.m_contrast); - settings.m_gamma = xml_get_attribute_float(screennode, "gamma", settings.m_gamma); - - // fetch positioning controls - settings.m_xoffset = xml_get_attribute_float(screennode, "hoffset", settings.m_xoffset); - settings.m_xscale = xml_get_attribute_float(screennode, "hstretch", settings.m_xscale); - settings.m_yoffset = xml_get_attribute_float(screennode, "voffset", settings.m_yoffset); - settings.m_yscale = xml_get_attribute_float(screennode, "vstretch", settings.m_yscale); - - // set the new values - container->set_user_settings(settings); - } -} - - -//------------------------------------------------- -// config_save - save data to the configuration -// file -//------------------------------------------------- - -void render_manager::config_save(int config_type, xml_data_node *parentnode) -{ - // we only care about game files - if (config_type != CONFIG_TYPE_GAME) - return; - - // write out the interface target - if (m_ui_target->index() != 0) - { - // create a node for it - xml_data_node *uinode = xml_add_child(parentnode, "interface", NULL); - if (uinode != NULL) - xml_set_attribute_int(uinode, "target", m_ui_target->index()); - } - - // iterate over targets - for (int targetnum = 0; targetnum < 1000; targetnum++) - { - // get this target and break when we fail - render_target *target = target_by_index(targetnum); - if (target == NULL) - break; - - // create a node - xml_data_node *targetnode = xml_add_child(parentnode, "target", NULL); - if (targetnode != NULL && !target->config_save(*targetnode)) - xml_delete_node(targetnode); - } - - // iterate over screen containers - int scrnum = 0; - for (render_container *container = m_screen_container_list.first(); container != NULL; container = container->next(), scrnum++) - { - // create a node - xml_data_node *screennode = xml_add_child(parentnode, "screen", NULL); - if (screennode != NULL) - { - bool changed = false; - - // output the basics - xml_set_attribute_int(screennode, "index", scrnum); - - render_container::user_settings settings; - container->get_user_settings(settings); - - // output the color controls - if (settings.m_brightness != machine().options().brightness()) - { - xml_set_attribute_float(screennode, "brightness", settings.m_brightness); - changed = true; - } - - if (settings.m_contrast != machine().options().contrast()) - { - xml_set_attribute_float(screennode, "contrast", settings.m_contrast); - changed = true; - } - - if (settings.m_gamma != machine().options().gamma()) - { - xml_set_attribute_float(screennode, "gamma", settings.m_gamma); - changed = true; - } - - // output the positioning controls - if (settings.m_xoffset != 0.0f) - { - xml_set_attribute_float(screennode, "hoffset", settings.m_xoffset); - changed = true; - } - - if (settings.m_xscale != 1.0f) - { - xml_set_attribute_float(screennode, "hstretch", settings.m_xscale); - changed = true; - } - - if (settings.m_yoffset != 0.0f) - { - xml_set_attribute_float(screennode, "voffset", settings.m_yoffset); - changed = true; - } - - if (settings.m_yscale != 1.0f) - { - xml_set_attribute_float(screennode, "vstretch", settings.m_yscale); - changed = true; - } - - // if nothing changed, kill the node - if (!changed) - xml_delete_node(screennode); - } - } -} |
