summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/render.c
diff options
context:
space:
mode:
author Miodrag Milanovic <mmicko@gmail.com>2015-11-08 12:56:12 +0100
committer Miodrag Milanovic <mmicko@gmail.com>2015-11-08 12:56:12 +0100
commit7c19aac60e12d6f5ea301bdb34d7826a01e0b06f (patch)
treef310d86aa2c6bfc19d115307dedde4eb0cd52dad /src/emu/render.c
parenta57b46ae933badd7441ce1644711dbb851e2b504 (diff)
Rename *.c -> *.cpp in our source (nw)
Diffstat (limited to 'src/emu/render.c')
-rw-r--r--src/emu/render.c2801
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);
- }
- }
-}