diff --git a/scripts/build/complay.py b/scripts/build/complay.py index 9932c604cb4..8ac24bb005a 100644 --- a/scripts/build/complay.py +++ b/scripts/build/complay.py @@ -93,7 +93,8 @@ class XmlError(Exception): class LayoutChecker(Minifyer): BADTAGPATTERN = re.compile('[^abcdefghijklmnopqrstuvwxyz0123456789_.:^$]') - VARPATTERN = re.compile('^~scr(0|[1-9][0-9]*)(native[xy]aspect|width|height)~$') + VARPATTERN = re.compile('^.*~[0-9A-Za-z_]+~.*$') + FLOATCHARS = re.compile('^.*[.eE].*$') SHAPES = frozenset(('disk', 'led14seg', 'led14segsc', 'led16seg', 'led16segsc', 'led7seg', 'led8seg_gts1', 'rect')) OBJECTS = frozenset(('backdrop', 'bezel', 'cpanel', 'marquee', 'overlay')) @@ -106,8 +107,6 @@ class LayoutChecker(Minifyer): self.views = { } self.referenced_elements = { } self.referenced_groups = { } - self.have_bounds = [ ] - self.have_color = [ ] def formatLocation(self): return '%s:%d:%d' % (self.locator.getSystemId(), self.locator.getLineNumber(), self.locator.getColumnNumber()) @@ -116,36 +115,125 @@ class LayoutChecker(Minifyer): self.errors += 1 sys.stderr.write('error: %s: %s\n' % (self.formatLocation(), msg)) - def checkBoundsDimension(self, attrs, name): - if name in attrs: - try: - return float(attrs[name]) - except: - if not self.VARPATTERN.match(attrs[name]): - self.handleError('Element bounds attribute %s "%s" is not numeric' % (name, attrs[name])) - return None + def checkIntAttribute(self, name, attrs, key, default): + if key not in attrs: + return default + val = attrs[key] + if self.VARPATTERN.match(val): + return None + base = 10 + offs = 0 + if (len(val) >= 1) and ('$' == val[0]): + base = 16 + offs = 1 + elif (len(val) >= 2) and ('0' == val[0]) and (('x' == val[1]) or ('X' == val[1])): + base = 16 + offs = 2 + elif (len(val) >= 1) and ('#' == val[0]): + offs = 1 + try: + return int(val[offs:], base) + except: + self.handleError('Element %s attribute %s "%s" is not an integer' % (name, key, val)) + return None + + def checkFloatAttribute(self, name, attrs, key, default): + if key not in attrs: + return default + val = attrs[key] + if self.VARPATTERN.match(val): + return None + try: + return float(val) + except: + self.handleError('Element %s attribute %s "%s" is not a floating point number' % (name, key, val)) + return None + + def checkNumericAttribute(self, name, attrs, key, default): + if key not in attrs: + return default + val = attrs[key] + if self.VARPATTERN.match(val): + return None + base = 0 + offs = 0 + try: + if (len(val) >= 1) and ('$' == val[0]): + base = 16 + offs = 1 + elif (len(val) >= 2) and ('0' == val[0]) and (('x' == val[1]) or ('X' == val[1])): + base = 16 + offs = 2 + elif (len(val) >= 1) and ('#' == val[0]): + base = 10 + offs = 1 + elif self.FLOATCHARS.match(val): + return float(val) + return int(val[offs:], base) + except: + self.handleError('Element %s attribute %s "%s" is not a number' % (name, key, val)) + return None + + def checkParameter(self, attrs): + if 'name' not in attrs: + self.handleError('Element param missing attribute name') + else: + name = attrs['name'] + self.checkNumericAttribute('param', attrs, 'increment', None) + lshift = self.checkIntAttribute('param', attrs, 'lshift', None) + if (lshift is not None) and (0 > lshift): + self.handleError('Element param attribute lshift "%s" is negative', (attrs['lshift'], )) + rshift = self.checkIntAttribute('param', attrs, 'rshift', None) + if (rshift is not None) and (0 > rshift): + self.handleError('Element param attribute rshift "%s" is negative', (attrs['rshift'], )) + if self.repeat_depth and self.repeat_depth[-1]: + if 'start' in attrs: + if 'value' in attrs: + self.handleError('Element param has both start and value attributes') + if 'name' in attrs: + if name not in self.variable_scopes[-1]: + self.variable_scopes[-1][name] = True + elif not self.VARPATTERN.match(name): + self.handleError('Incrementing parameter "%s" redefined', (name, )) + else: + if 'value' not in attrs: + self.handleError('Element param missing attribute value') + if ('increment' in attrs) or ('lshift' in attrs) or ('rshift' in attrs): + self.handleError('Element param has increment/lshift/rshift attribute(s) without start attribute') + if 'name' in attrs: + if not self.variable_scopes[-1].get(name, False): + self.variable_scopes[-1][name] = False + elif not self.VARPATTERN.match(name): + self.handleError('Incrementing parameter "%s" redefined', (name, )) + else: + if ('start' in attrs) or ('increment' in attrs) or ('lshift' in attrs) or ('rshift' in attrs): + self.handleError('Element param with start/increment/lshift/rshift attribute(s) not in repeat scope') + if 'value' not in attrs: + self.handleError('Element param missing attribute value') + if 'name' in attrs: + self.variable_scopes[-1][attrs['name']] = False def checkBounds(self, attrs): if self.have_bounds[-1]: self.handleError('Duplicate element bounds') else: self.have_bounds[-1] = True - left = self.checkBoundsDimension(attrs, 'left') - top = self.checkBoundsDimension(attrs, 'top') - right = self.checkBoundsDimension(attrs, 'right') - bottom = self.checkBoundsDimension(attrs, 'bottom') - x = self.checkBoundsDimension(attrs, 'bottom') - y = self.checkBoundsDimension(attrs, 'bottom') - width = self.checkBoundsDimension(attrs, 'width') - height = self.checkBoundsDimension(attrs, 'height') + left = self.checkFloatAttribute('bounds', attrs, 'left', 0.0) + top = self.checkFloatAttribute('bounds', attrs, 'top', 0.0) + right = self.checkFloatAttribute('bounds', attrs, 'right', 1.0) + bottom = self.checkFloatAttribute('bounds', attrs, 'bottom', 1.0) + x = self.checkFloatAttribute('bounds', attrs, 'x', 0.0) + y = self.checkFloatAttribute('bounds', attrs, 'y', 0.0) + width = self.checkFloatAttribute('bounds', attrs, 'width', 1.0) + height = self.checkFloatAttribute('bounds', attrs, 'height', 1.0) if (left is not None) and (right is not None) and (left > right): self.handleError('Element bounds attribute left "%s" is greater than attribute right "%s"' % ( - attrs['left'], - attrs['right'])) + attrs.get('left', 0.0), + attrs.get('right', 1.0))) if (top is not None) and (bottom is not None) and (top > bottom): self.handleError('Element bounds attribute top "%s" is greater than attribute bottom "%s"' % ( - attrs['top'], - attrs['bottom'])) + attrs.get('top', 0.0), + attrs.get('bottom', 1.0))) if (width is not None) and (0.0 > width): self.handleError('Element bounds attribute width "%s" is negative' % (attrs['width'], )) if (height is not None) and (0.0 > height): @@ -155,16 +243,12 @@ class LayoutChecker(Minifyer): has_ltrb = ('left' in attrs) or ('top' in attrs) or ('right' in attrs) or ('bottom' in attrs) has_origin_size = ('x' in attrs) or ('y' in attrs) or ('width' in attrs) or ('height' in attrs) if has_ltrb and has_origin_size: - self.handleError('Element bounds has both left/top/right/bottom and origin/size') + self.handleError('Element bounds has both left/top/right/bottom and origin/size attributes') def checkColorChannel(self, attrs, name): - if name in attrs: - try: - channel = float(attrs[name]) - if (0.0 > channel) or (1.0 < channel): - self.handleError('Element color attribute %s "%s" outside valid range 0.0-1.0' % (name, attrs[name])) - except: - self.handleError('Element color attribute %s "%s" is not numeric' % (name, attrs[name])) + channel = self.checkFloatAttribute('color', attrs, name, None) + if (channel is not None) and ((0.0 > channel) or (1.0 < channel)): + self.handleError('Element color attribute %s "%s" outside valid range 0.0-1.0' % (name, attrs[name])) def checkTag(self, tag, element, attr): if '' == tag: @@ -177,7 +261,118 @@ class LayoutChecker(Minifyer): if tag.find('::') >= 0: self.handleError('Element %s attribute %s "%s" contains double separator' % (element, attr, tag)) - def checkGroupViewItem(self, name, attrs): + def rootStartHandler(self, name, attrs): + if 'mamelayout' != name: + self.ignored_depth = 1 + self.handleError('Expected root element mamelayout but found %s' % (name, )) + else: + if 'version' not in attrs: + self.handleError('Element mamelayout missing attribute version') + else: + try: + long(attrs['version']) + except: + self.handleError('Element mamelayout attribute version "%s" is not an integer' % (attrs['version'], )) + self.variable_scopes.append({ }) + self.handlers.append((self.layoutStartHandler, self.layoutEndHandler)) + + def rootEndHandler(self, name, attrs): + pass # should be unreachable + + def layoutStartHandler(self, name, attrs): + if 'element' == name: + if 'name' not in attrs: + self.handleError('Element element missing attribute name') + else: + if attrs['name'] not in self.elements: + self.elements[attrs['name']] = self.formatLocation() + elif not self.VARPATTERN.match(attrs['name']): + self.handleError('Element element has duplicate name (previous %s)' % (self.elements[attrs['name']], )) + self.handlers.append((self.elementStartHandler, self.elementEndHandler)) + elif 'group' == name: + if 'name' not in attrs: + self.handleError('Element group missing attribute name') + else: + if attrs['name'] not in self.groups: + self.groups[attrs['name']] = self.formatLocation() + elif not self.VARPATTERN.match(attrs['name']): + self.handleError('Element group has duplicate name (previous %s)' % (self.groups[attrs['name']], )) + self.handlers.append((self.groupViewStartHandler, self.groupViewEndHandler)) + self.variable_scopes.append({ }) + self.repeat_depth.append(0) + self.have_bounds.append(False) + elif 'view' == name: + if 'name' not in attrs: + self.handleError('Element view missing attribute name') + else: + if attrs['name'] not in self.views: + self.views[attrs['name']] = self.formatLocation() + elif not self.VARPATTERN.match(attrs['name']): + self.handleError('Element view has duplicate name (previous %s)' % (self.views[attrs['name']], )) + self.handlers.append((self.groupViewStartHandler, self.groupViewEndHandler)) + self.variable_scopes.append({ }) + self.repeat_depth.append(0) + self.have_bounds.append(False) + elif 'param' == name: + self.checkParameter(attrs) + self.ignored_depth = 1 + elif 'script' == name: + self.ignored_depth = 1 + else: + self.handleError('Encountered unexpected element %s' % (name, )) + self.ignored_depth = 1 + + def layoutEndHandler(self, name): + for element in self.referenced_elements: + if (element not in self.elements) and (not self.VARPATTERN.match(element)): + self.handleError('Element "%s" not found (first referenced at %s)' % (element, self.referenced_elements[element])) + for group in self.referenced_groups: + if (group not in self.groups) and (not self.VARPATTERN.match(group)): + self.handleError('Group "%s" not found (first referenced at %s)' % (group, self.referenced_groups[group])) + self.variable_scopes.pop() + self.handlers.pop() + + def elementStartHandler(self, name, attrs): + if name in self.SHAPES: + self.handlers.append((self.shapeStartHandler, self.shapeEndHandler)) + self.have_bounds.append(False) + self.have_color.append(False) + elif 'text' == name: + if 'string' not in attrs: + self.handleError('Element bounds missing attribute string') + if 'align' in attrs: + align = self.checkIntAttribute(name, attrs, 'align', None) + if (align is not None) and ((0 > align) or (2 < align)): + self.handleError('Element text attribute align "%s" not in valid range 0-2' % (attrs['align'], )) + self.handlers.append((self.shapeStartHandler, self.shapeEndHandler)) + self.have_bounds.append(False) + self.have_color.append(False) + else: + self.ignored_depth = 1 + + def elementEndHandler(self, name): + self.handlers.pop() + + def shapeStartHandler(self, name, attrs): + if 'bounds' == name: + self.checkBounds(attrs) + elif 'color' == name: + if self.have_color[-1]: + self.handleError('Duplicate bounds element') + else: + self.have_color[-1] = True + self.checkColorChannel(attrs, 'red') + self.checkColorChannel(attrs, 'green') + self.checkColorChannel(attrs, 'blue') + self.checkColorChannel(attrs, 'alpha') + self.ignored_depth = 1 + + def shapeEndHandler(self, name): + self.have_bounds.pop() + self.have_color.pop() + self.handlers.pop() + + def groupViewStartHandler(self, name, attrs): if name in self.OBJECTS: if 'element' not in attrs: self.handleError('Element %s missing attribute element', (name, )) @@ -187,21 +382,14 @@ class LayoutChecker(Minifyer): if 'inputmask' not in attrs: self.handleError('Element %s has inputtag without inputmask attribute' % (name, )) self.checkTag(attrs['inputtag'], name, 'inputtag') - if 'inputmask' in attrs: - try: - int(attrs['inputmask'], 0) - except: - self.handleError('Element %s attribute inputmask "%s" is not an integer' % (name, attrs['inputmask'])) - self.in_object = True + self.checkIntAttribute(name, attrs, 'inputmask', None) + self.handlers.append((self.objectStartHandler, self.objectEndHandler)) self.have_bounds.append(False) elif 'screen' == name: if 'index' in attrs: - try: - index = long(attrs['index'], 0) - if 0 > index: - self.handleError('Element screen attribute index "%s" is negative' % (attrs['index'], )) - except: - self.handleError('Element screen attribute index "%s" is not an integer' % (attrs['index'], )) + index = self.checkIntAttribute(name, attrs, 'index', None) + if (index is not None) and (0 > index): + self.handleError('Element screen attribute index "%s" is negative' % (attrs['index'], )) if 'tag' in attrs: self.handleError('Element screen has both index and tag attributes') if 'tag' in attrs: @@ -209,34 +397,65 @@ class LayoutChecker(Minifyer): self.checkTag(tag, name, 'tag') if self.BADTAGPATTERN.search(tag): self.handleError('Element screen attribute tag "%s" contains invalid characters' % (tag, )) - self.in_object = True + self.handlers.append((self.objectStartHandler, self.objectEndHandler)) self.have_bounds.append(False) elif 'group' == name: if 'ref' not in attrs: self.handleError('Element group missing attribute ref') elif attrs['ref'] not in self.referenced_groups: self.referenced_groups[attrs['ref']] = self.formatLocation() - self.in_object = True + self.handlers.append((self.objectStartHandler, self.objectEndHandler)) self.have_bounds.append(False) + elif 'repeat' == name: + if 'count' not in attrs: + self.handleError('Element repeat missing attribute count') + else: + count = self.checkIntAttribute(name, attrs, 'count', None) + if (count is not None) and (0 >= count): + self.handleError('Element repeat attribute count "%s" is negative' % (attrs['count'], )) + self.variable_scopes.append({ }) + self.repeat_depth[-1] += 1 + elif 'param' == name: + self.checkParameter(attrs) + self.ignored_depth = 1 elif 'bounds' == name: self.checkBounds(attrs) + if self.repeat_depth[-1]: + self.handleError('Element bounds inside repeat') self.ignored_depth = 1 else: self.handleError('Encountered unexpected element %s' % (name, )) self.ignored_depth = 1 + def groupViewEndHandler(self, name): + self.variable_scopes.pop() + if self.repeat_depth[-1]: + self.repeat_depth[-1] -= 1 + else: + self.repeat_depth.pop() + self.have_bounds.pop() + self.handlers.pop() + + def objectStartHandler(self, name, attrs): + if 'bounds' == name: + self.checkBounds(attrs) + self.ignored_depth = 1 + + def objectEndHandler(self, name): + self.have_bounds.pop() + self.handlers.pop() + def setDocumentLocator(self, locator): self.locator = locator super(LayoutChecker, self).setDocumentLocator(locator) def startDocument(self): - self.in_layout = False - self.in_element = False - self.in_group = False - self.in_view = False - self.in_shape = False - self.in_object = False + self.handlers = [(self.rootStartHandler, self.rootEndHandler)] self.ignored_depth = 0 + self.variable_scopes = [ ] + self.repeat_depth = [ ] + self.have_bounds = [ ] + self.have_color = [ ] super(LayoutChecker, self).startDocument() def endDocument(self): @@ -246,127 +465,26 @@ class LayoutChecker(Minifyer): self.views.clear() self.referenced_elements.clear() self.referenced_groups.clear() - del self.have_bounds[:] - del self.have_color[:] + del self.handlers + del self.ignored_depth + del self.variable_scopes + del self.repeat_depth + del self.have_bounds + del self.have_color super(LayoutChecker, self).endDocument() def startElement(self, name, attrs): if 0 < self.ignored_depth: self.ignored_depth += 1 - elif not self.in_layout: - if 'mamelayout' != name: - self.ignored_depth = 1 - self.handleError('Expected root element mamelayout but found %s' % (name, )) - else: - if 'version' not in attrs: - self.handleError('Element mamelayout missing attribute version') - else: - try: - long(attrs['version']) - except: - self.handleError('Element mamelayout attribute version "%s" is not an integer' % (attrs['version'], )) - self.in_layout = True - elif self.in_object: - if 'bounds' == name: - self.checkBounds(attrs) - self.ignored_depth = 1 - elif self.in_shape: - if 'bounds' == name: - self.checkBounds(attrs) - elif 'color' == name: - if self.have_color[-1]: - self.handleError('Duplicate bounds element') - else: - self.have_color[-1] = True - self.checkColorChannel(attrs, 'red') - self.checkColorChannel(attrs, 'green') - self.checkColorChannel(attrs, 'blue') - self.checkColorChannel(attrs, 'alpha') - self.ignored_depth = 1 - elif self.in_element: - if name in self.SHAPES: - self.in_shape = True - self.have_bounds.append(False) - self.have_color.append(False) - elif 'text' == name: - if 'string' not in attrs: - self.handleError('Element bounds missing attribute string') - if 'align' in attrs: - try: - align = long(attrs['align']) - if (0 > align) or (2 < align): - self.handleError('Element text attribute align "%s" not in valid range 0-2' % (attrs['align'], )) - except: - self.handleError('Element text attribute align "%s" is not an integer' % (attrs['align'], )) - self.in_shape = True - self.have_bounds.append(False) - self.have_color.append(False) - else: - self.ignored_depth = 1 - elif self.in_group or self.in_view: - self.checkGroupViewItem(name, attrs) - elif 'element' == name: - if 'name' not in attrs: - self.handleError('Element element missing attribute name') - else: - if attrs['name'] in self.elements: - self.handleError('Element element has duplicate name (previous %s)' % (self.elements[attrs['name']], )) - else: - self.elements[attrs['name']] = self.formatLocation() - self.in_element = True - elif 'group' == name: - if 'name' not in attrs: - self.handleError('Element group missing attribute name') - else: - if attrs['name'] in self.groups: - self.handleError('Element group has duplicate name (previous %s)' % (self.groups[attrs['name']], )) - else: - self.groups[attrs['name']] = self.formatLocation() - self.in_group = True - self.have_bounds.append(False) - elif 'view' == name: - if 'name' not in attrs: - self.handleError('Element view missing attribute name') - else: - if attrs['name'] in self.views: - self.handleError('Element view has duplicate name (previous %s)' % (self.views[attrs['name']], )) - else: - self.views[attrs['name']] = self.formatLocation() - self.in_view = True - self.have_bounds.append(False) - elif 'script' == name: - self.ignored_depth = 1 else: - self.handleError('Encountered unexpected element %s' % (name, )) - self.ignored_depth = 1 + self.handlers[-1][0](name, attrs) super(LayoutChecker, self).startElement(name, attrs) def endElement(self, name): if 0 < self.ignored_depth: self.ignored_depth -= 1 - elif self.in_object: - self.in_object = False - self.have_bounds.pop() - elif self.in_shape: - self.in_shape = False - self.have_bounds.pop() - self.have_color.pop() - elif self.in_element: - self.in_element = False - elif self.in_group: - self.in_group = False - self.have_bounds.pop() - elif self.in_view: - self.in_view = False - self.have_bounds.pop() - elif self.in_layout: - for element in self.referenced_elements: - if element not in self.elements: - self.handleError('Element "%s" not found (first referenced at %s)' % (element, self.referenced_elements[element])) - for group in self.referenced_groups: - if group not in self.groups: - self.handleError('Group "%s" not found (first referenced at %s)' % (group, self.referenced_groups[group])) - self.in_layout = False + else: + self.handlers[-1][1](name) super(LayoutChecker, self).endElement(name) diff --git a/src/devices/machine/ie15.cpp b/src/devices/machine/ie15.cpp index 308c059de38..6b60489504d 100644 --- a/src/devices/machine/ie15.cpp +++ b/src/devices/machine/ie15.cpp @@ -604,13 +604,13 @@ ROM_START( ie15 ) ROM_END MACHINE_CONFIG_START(ie15_device::device_add_mconfig) - ie15core(config); - MCFG_SCREEN_ADD_MONOCHROME("screen", RASTER, rgb_t::green()) MCFG_SCREEN_UPDATE_DRIVER(ie15_device, screen_update) - MCFG_SCREEN_RAW_PARAMS(XTAL(30'800'000)/2, IE15_TOTAL_HORZ, IE15_HORZ_START, - IE15_HORZ_START+IE15_DISP_HORZ, IE15_TOTAL_VERT, IE15_VERT_START, - IE15_VERT_START+IE15_DISP_VERT); + MCFG_SCREEN_RAW_PARAMS(XTAL(30'800'000)/2, + IE15_TOTAL_HORZ, IE15_HORZ_START, IE15_HORZ_START+IE15_DISP_HORZ, + IE15_TOTAL_VERT, IE15_VERT_START, IE15_VERT_START+IE15_DISP_VERT); + + ie15core(config); MCFG_DEVICE_ADD("gfxdecode", GFXDECODE, "palette", gfx_ie15) MCFG_PALETTE_ADD_MONOCHROME("palette") diff --git a/src/emu/layout/quadhsxs.lay b/src/emu/layout/quadhsxs.lay index b07a04e7b11..a5a347299cb 100644 --- a/src/emu/layout/quadhsxs.lay +++ b/src/emu/layout/quadhsxs.lay @@ -1,53 +1,5 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emu/render.cpp b/src/emu/render.cpp index f1ce0b1fc8e..9ec8445fa49 100644 --- a/src/emu/render.cpp +++ b/src/emu/render.cpp @@ -79,7 +79,7 @@ enum //************************************************************************** // an object_transform is used to track transformations when building an object list -struct object_transform +struct render_target::object_transform { float xoffs, yoffs; // offset transforms float xscale, yscale; // scale transforms diff --git a/src/emu/render.h b/src/emu/render.h index 66c885a4c78..e07e7e7cad7 100644 --- a/src/emu/render.h +++ b/src/emu/render.h @@ -57,6 +57,9 @@ #include +namespace emu { namespace render { namespace detail { class layout_environment; } } } + + //************************************************************************** // CONSTANTS //************************************************************************** @@ -127,41 +130,38 @@ constexpr u32 PRIMFLAG_PACKABLE = 1 << PRIMFLAG_PACKABLE_SHIFT; // MACROS //************************************************************************** -#define PRIMFLAG_TEXORIENT(x) ((x) << PRIMFLAG_TEXORIENT_SHIFT) -#define PRIMFLAG_GET_TEXORIENT(x) (((x) & PRIMFLAG_TEXORIENT_MASK) >> PRIMFLAG_TEXORIENT_SHIFT) +constexpr u32 PRIMFLAG_TEXORIENT(u32 x) { return x << PRIMFLAG_TEXORIENT_SHIFT; } +constexpr u32 PRIMFLAG_GET_TEXORIENT(u32 x) { return (x & PRIMFLAG_TEXORIENT_MASK) >> PRIMFLAG_TEXORIENT_SHIFT; } -#define PRIMFLAG_TEXFORMAT(x) ((x) << PRIMFLAG_TEXFORMAT_SHIFT) -#define PRIMFLAG_GET_TEXFORMAT(x) (((x) & PRIMFLAG_TEXFORMAT_MASK) >> PRIMFLAG_TEXFORMAT_SHIFT) +constexpr u32 PRIMFLAG_TEXFORMAT(u32 x) { return x << PRIMFLAG_TEXFORMAT_SHIFT; } +constexpr u32 PRIMFLAG_GET_TEXFORMAT(u32 x) { return (x & PRIMFLAG_TEXFORMAT_MASK) >> PRIMFLAG_TEXFORMAT_SHIFT; } -#define PRIMFLAG_BLENDMODE(x) ((x) << PRIMFLAG_BLENDMODE_SHIFT) -#define PRIMFLAG_GET_BLENDMODE(x) (((x) & PRIMFLAG_BLENDMODE_MASK) >> PRIMFLAG_BLENDMODE_SHIFT) +constexpr u32 PRIMFLAG_BLENDMODE(u32 x) { return x << PRIMFLAG_BLENDMODE_SHIFT; } +constexpr u32 PRIMFLAG_GET_BLENDMODE(u32 x) { return (x & PRIMFLAG_BLENDMODE_MASK) >> PRIMFLAG_BLENDMODE_SHIFT; } -#define PRIMFLAG_ANTIALIAS(x) ((x) << PRIMFLAG_ANTIALIAS_SHIFT) -#define PRIMFLAG_GET_ANTIALIAS(x) (((x) & PRIMFLAG_ANTIALIAS_MASK) >> PRIMFLAG_ANTIALIAS_SHIFT) +constexpr u32 PRIMFLAG_ANTIALIAS(u32 x) { return x << PRIMFLAG_ANTIALIAS_SHIFT; } +constexpr u32 PRIMFLAG_GET_ANTIALIAS(u32 x) { return (x & PRIMFLAG_ANTIALIAS_MASK) >> PRIMFLAG_ANTIALIAS_SHIFT; } -#define PRIMFLAG_SCREENTEX(x) ((x) << PRIMFLAG_SCREENTEX_SHIFT) -#define PRIMFLAG_GET_SCREENTEX(x) (((x) & PRIMFLAG_SCREENTEX_MASK) >> PRIMFLAG_SCREENTEX_SHIFT) +constexpr u32 PRIMFLAG_SCREENTEX(u32 x) { return x << PRIMFLAG_SCREENTEX_SHIFT; } +constexpr u32 PRIMFLAG_GET_SCREENTEX(u32 x) { return (x & PRIMFLAG_SCREENTEX_MASK) >> PRIMFLAG_SCREENTEX_SHIFT; } -#define PRIMFLAG_TEXWRAP(x) ((x) << PRIMFLAG_TEXWRAP_SHIFT) -#define PRIMFLAG_GET_TEXWRAP(x) (((x) & PRIMFLAG_TEXWRAP_MASK) >> PRIMFLAG_TEXWRAP_SHIFT) +constexpr u32 PRIMFLAG_TEXWRAP(u32 x) { return x << PRIMFLAG_TEXWRAP_SHIFT; } +constexpr u32 PRIMFLAG_GET_TEXWRAP(u32 x) { return (x & PRIMFLAG_TEXWRAP_MASK) >> PRIMFLAG_TEXWRAP_SHIFT; } -#define PRIMFLAG_TEXSHADE(x) ((x) << PRIMFLAG_TEXSHADE_SHIFT) -#define PRIMFLAG_GET_TEXSHADE(x) (((x) & PRIMFLAG_TEXSHADE_MASK) >> PRIMFLAG_TEXSHADE_SHIFT) +constexpr u32 PRIMFLAG_TEXSHADE(u32 x) { return x << PRIMFLAG_TEXSHADE_SHIFT; } +constexpr u32 PRIMFLAG_GET_TEXSHADE(u32 x) { return (x & PRIMFLAG_TEXSHADE_MASK) >> PRIMFLAG_TEXSHADE_SHIFT; } -#define PRIMFLAG_VECTOR(x) ((x) << PRIMFLAG_VECTOR_SHIFT) -#define PRIMFLAG_GET_VECTOR(x) (((x) & PRIMFLAG_VECTOR_MASK) >> PRIMFLAG_VECTOR_SHIFT) +constexpr u32 PRIMFLAG_VECTOR(u32 x) { return x << PRIMFLAG_VECTOR_SHIFT; } +constexpr u32 PRIMFLAG_GET_VECTOR(u32 x) { return (x & PRIMFLAG_VECTOR_MASK) >> PRIMFLAG_VECTOR_SHIFT; } -#define PRIMFLAG_VECTORBUF(x) ((x) << PRIMFLAG_VECTORBUF_SHIFT) -#define PRIMFLAG_GET_VECTORBUF(x) (((x) & PRIMFLAG_VECTORBUF_MASK) >> PRIMFLAG_VECTORBUF_SHIFT) +constexpr u32 PRIMFLAG_VECTORBUF(u32 x) { return x << PRIMFLAG_VECTORBUF_SHIFT; } +constexpr u32 PRIMFLAG_GET_VECTORBUF(u32 x) { return (x & PRIMFLAG_VECTORBUF_MASK) >> PRIMFLAG_VECTORBUF_SHIFT; } //************************************************************************** // TYPE DEFINITIONS //************************************************************************** -// private classes declared in render.cpp -struct object_transform; - // texture scaling callback typedef void (*texture_scaler_func)(bitmap_argb32 &dest, bitmap_argb32 &source, const rectangle &sbounds, void *param); @@ -173,8 +173,8 @@ struct render_bounds float x1; // rightmost X coordinate float y1; // bottommost Y coordinate - float width() const { return x1 - x0; } - float height() const { return y1 - y0; } + constexpr float width() const { return x1 - x0; } + constexpr float height() const { return y1 - y0; } }; @@ -232,12 +232,10 @@ class render_screen_list public: // construction/destruction - item(screen_device &screen) - : m_next(nullptr), - m_screen(screen) { } + item(screen_device &screen) : m_screen(screen) { } // state - item * m_next; // next screen in list + item * m_next = nullptr; // next screen in list screen_device & m_screen; // reference to screen device }; @@ -253,7 +251,7 @@ public: int contains(screen_device &screen) const { int count = 0; - for (item *curitem = m_list.first(); curitem != nullptr; curitem = curitem->m_next) + for (item *curitem = m_list.first(); curitem; curitem = curitem->m_next) if (&curitem->m_screen == &screen) count++; return count; } @@ -269,6 +267,7 @@ private: // render_layer_config - describes the state of layers class render_layer_config { +private: static constexpr u8 ENABLE_BACKDROP = 0x01; // enable backdrop layers static constexpr u8 ENABLE_OVERLAY = 0x02; // enable overlay layers static constexpr u8 ENABLE_BEZEL = 0x04; // enable bezel layers @@ -278,31 +277,36 @@ class render_layer_config static constexpr u8 ENABLE_SCREEN_OVERLAY = 0x40; // enable screen overlays static constexpr u8 DEFAULT = ENABLE_BACKDROP | ENABLE_OVERLAY | ENABLE_BEZEL | ENABLE_CPANEL | ENABLE_MARQUEE | ENABLE_SCREEN_OVERLAY; + u8 m_state = DEFAULT; + + render_layer_config &set_flag(u8 flag, bool enable) + { + if (enable) m_state |= flag; + else m_state &= ~flag; + return *this; + } + public: - render_layer_config() - : m_state(DEFAULT) { } + constexpr render_layer_config() { } bool operator==(const render_layer_config &rhs) const { return m_state == rhs.m_state; } bool operator!=(const render_layer_config &rhs) const { return m_state != rhs.m_state; } - bool backdrops_enabled() const { return ((m_state & ENABLE_BACKDROP) != 0); } - bool overlays_enabled() const { return ((m_state & ENABLE_OVERLAY) != 0); } - bool bezels_enabled() const { return ((m_state & ENABLE_BEZEL) != 0); } - bool cpanels_enabled() const { return ((m_state & ENABLE_CPANEL) != 0); } - bool marquees_enabled() const { return ((m_state & ENABLE_MARQUEE) != 0); } - bool screen_overlay_enabled() const { return ((m_state & ENABLE_SCREEN_OVERLAY) != 0); } - bool zoom_to_screen() const { return ((m_state & ZOOM_TO_SCREEN) != 0); } + constexpr bool backdrops_enabled() const { return (m_state & ENABLE_BACKDROP) != 0; } + constexpr bool overlays_enabled() const { return (m_state & ENABLE_OVERLAY) != 0; } + constexpr bool bezels_enabled() const { return (m_state & ENABLE_BEZEL) != 0; } + constexpr bool cpanels_enabled() const { return (m_state & ENABLE_CPANEL) != 0; } + constexpr bool marquees_enabled() const { return (m_state & ENABLE_MARQUEE) != 0; } + constexpr bool screen_overlay_enabled() const { return (m_state & ENABLE_SCREEN_OVERLAY) != 0; } + constexpr bool zoom_to_screen() const { return (m_state & ZOOM_TO_SCREEN) != 0; } - render_layer_config &set_backdrops_enabled(bool enable) { if (enable) m_state |= ENABLE_BACKDROP; else m_state &= ~ENABLE_BACKDROP; return *this; } - render_layer_config &set_overlays_enabled(bool enable) { if (enable) m_state |= ENABLE_OVERLAY; else m_state &= ~ENABLE_OVERLAY; return *this; } - render_layer_config &set_bezels_enabled(bool enable) { if (enable) m_state |= ENABLE_BEZEL; else m_state &= ~ENABLE_BEZEL; return *this; } - render_layer_config &set_cpanels_enabled(bool enable) { if (enable) m_state |= ENABLE_CPANEL; else m_state &= ~ENABLE_CPANEL; return *this; } - render_layer_config &set_marquees_enabled(bool enable) { if (enable) m_state |= ENABLE_MARQUEE; else m_state &= ~ENABLE_MARQUEE; return *this; } - render_layer_config &set_screen_overlay_enabled(bool enable) { if (enable) m_state |= ENABLE_SCREEN_OVERLAY; else m_state &= ~ENABLE_SCREEN_OVERLAY; return *this; } - render_layer_config &set_zoom_to_screen(bool zoom) { if (zoom) m_state |= ZOOM_TO_SCREEN; else m_state &= ~ZOOM_TO_SCREEN; return *this; } - -private: - u8 m_state; + render_layer_config &set_backdrops_enabled(bool enable) { return set_flag(ENABLE_BACKDROP, enable); } + render_layer_config &set_overlays_enabled(bool enable) { return set_flag(ENABLE_OVERLAY, enable); } + render_layer_config &set_bezels_enabled(bool enable) { return set_flag(ENABLE_BEZEL, enable); } + render_layer_config &set_cpanels_enabled(bool enable) { return set_flag(ENABLE_CPANEL, enable); } + render_layer_config &set_marquees_enabled(bool enable) { return set_flag(ENABLE_MARQUEE, enable); } + render_layer_config &set_screen_overlay_enabled(bool enable) { return set_flag(ENABLE_SCREEN_OVERLAY, enable); } + render_layer_config &set_zoom_to_screen(bool zoom) { return set_flag(ZOOM_TO_SCREEN, zoom); } }; @@ -314,13 +318,7 @@ class render_primitive friend class simple_list; public: - render_primitive(): - type(), - flags(0), - width(0), - container(nullptr), - m_next(nullptr) - {} + render_primitive() { } // render primitive types enum primitive_type @@ -342,19 +340,19 @@ public: void reset(); // public state - primitive_type type; // type of primitive + primitive_type type = INVALID; // type of primitive render_bounds bounds; // bounds or positions render_bounds full_bounds; // bounds or positions (unclipped) render_color color; // RGBA values - u32 flags; // flags - float width; // width (for line primitives) + u32 flags = 0U; // flags + float width = 0.0F; // width (for line primitives) render_texinfo texture; // texture info (for quad primitives) render_quad_texuv texcoords; // texture coordinates (for quad primitives) - render_container * container; // the render container we belong to + render_container * container = nullptr;// the render container we belong to private: // internal state - render_primitive * m_next; // pointer to next element + render_primitive * m_next = nullptr; // pointer to next element }; @@ -459,7 +457,7 @@ private: struct scaled_texture { bitmap_argb32 * bitmap; // final bitmap - u32 seqid; // sequence number + u32 seqid; // sequence number }; // internal state @@ -468,12 +466,12 @@ private: bitmap_t * m_bitmap; // pointer to the original bitmap rectangle m_sbounds; // source bounds within the bitmap texture_format m_format; // format of the texture data - u64 m_osddata; // aux data to pass to osd + u64 m_osddata; // aux data to pass to osd // scaling state (ARGB32 only) texture_scaler_func m_scaler; // scaling callback void * m_param; // scaling callback parameter - u32 m_curseq; // current sequence number + u32 m_curseq; // current sequence number scaled_texture m_scaled[MAX_TEXTURE_SCALES];// array of scaled variants of this texture }; @@ -566,11 +564,11 @@ private: private: // internal state item * m_next; // pointer to the next element in the list - u8 m_type; // type of element + u8 m_type; // type of element render_bounds m_bounds; // bounds of the element render_color m_color; // RGBA factors - u32 m_flags; // option flags - u32 m_internal; // internal flags + u32 m_flags; // option flags + u32 m_internal; // internal flags float m_width; // width of the line (lines only) render_texture * m_texture; // pointer to the source texture (quads only) }; @@ -635,8 +633,10 @@ DECLARE_ENUM_INCDEC_OPERATORS(item_layer) class layout_element { public: + using environment = emu::render::detail::layout_environment; + // construction/destruction - layout_element(running_machine &machine, util::xml::data_node const &elemnode, const char *dirname); + layout_element(environment &env, util::xml::data_node const &elemnode, const char *dirname); virtual ~layout_element(); // getters @@ -659,7 +659,7 @@ private: typedef std::unique_ptr ptr; // construction/destruction - component(running_machine &machine, util::xml::data_node const &compnode, const char *dirname); + component(environment &env, util::xml::data_node const &compnode, const char *dirname); virtual ~component() = default; // setup @@ -727,13 +727,13 @@ private: int m_state; // associated state number }; - typedef component::ptr (*make_component_func)(running_machine &machine, util::xml::data_node const &compnode, const char *dirname); + typedef component::ptr (*make_component_func)(environment &env, util::xml::data_node const &compnode, const char *dirname); typedef std::map make_component_map; // internal helpers static void element_scale(bitmap_argb32 &dest, bitmap_argb32 &source, const rectangle &sbounds, void *param); - template static component::ptr make_component(running_machine &machine, util::xml::data_node const &compnode, const char *dirname); - template static component::ptr make_dotmatrix_component(running_machine &machine, util::xml::data_node const &compnode, const char *dirname); + template static component::ptr make_component(environment &env, util::xml::data_node const &compnode, const char *dirname); + template static component::ptr make_dotmatrix_component(environment &env, util::xml::data_node const &compnode, const char *dirname); static make_component_map const s_make_component; // maps component XML names to creator functions @@ -757,9 +757,10 @@ private: class layout_group { public: - typedef std::unordered_map group_map; + using environment = emu::render::detail::layout_environment; + using group_map = std::unordered_map; - layout_group(running_machine &machine, util::xml::data_node const &groupnode); + layout_group(util::xml::data_node const &groupnode); ~layout_group(); util::xml::data_node const &get_groupnode() const { return m_groupnode; } @@ -767,12 +768,19 @@ public: render_bounds make_transform(render_bounds const &dest) const; render_bounds make_transform(render_bounds const &dest, render_bounds const &transform) const; - void resolve_bounds(group_map &groupmap); + void set_bounds_unresolved(); + void resolve_bounds(environment &env, group_map &groupmap); private: - void resolve_bounds(group_map &groupmap, std::vector &seen); + void resolve_bounds(environment &env, group_map &groupmap, std::vector &seen); + void resolve_bounds( + environment &env, + util::xml::data_node const &parentnode, + group_map &groupmap, + std::vector &seen, + bool repeat, + bool init); - running_machine & m_machine; util::xml::data_node const & m_groupnode; render_bounds m_bounds; bool m_bounds_resolved; @@ -787,6 +795,7 @@ private: class layout_view { public: + using environment = emu::render::detail::layout_environment; using element_map = std::unordered_map; using group_map = std::unordered_map; @@ -806,7 +815,7 @@ public: public: // construction/destruction item( - device_t &device, + environment &env, util::xml::data_node const &itemnode, element_map &elemmap, render_bounds const &transform); @@ -846,10 +855,10 @@ public: // construction/destruction layout_view( - device_t &device, + environment &env, util::xml::data_node const &viewnode, element_map &elemmap, - group_map const &groupmap); + group_map &groupmap); ~layout_view(); // getters @@ -873,13 +882,16 @@ public: private: // add items, recursing for groups void add_items( - device_t &device, + environment &env, util::xml::data_node const &parentnode, element_map &elemmap, - group_map const &groupmap, - render_bounds const &transform); + group_map &groupmap, + render_bounds const &transform, + bool root, + bool repeat, + bool init); - static std::string make_name(device_t &device, util::xml::data_node const &viewnode); + static std::string make_name(environment &env, util::xml::data_node const &viewnode); // internal state std::string m_name; // name of the layout @@ -1014,6 +1026,9 @@ public: void resolve_tags(); private: + // private classes declared in render.cpp + struct object_transform; + // internal helpers enum constructor_impl_t { CONSTRUCTOR_IMPL }; template render_target(render_manager &manager, T&& layout, u32 flags, constructor_impl_t); diff --git a/src/emu/rendlay.cpp b/src/emu/rendlay.cpp index e245aebf2dd..d07c07704a6 100644 --- a/src/emu/rendlay.cpp +++ b/src/emu/rendlay.cpp @@ -15,12 +15,21 @@ #include "rendfont.h" #include "rendlay.h" #include "rendutil.h" +#include "vecstream.h" #include "xmlfile.h" #include +#include +#include +#include +#include +#include +#include #include #include +#include #include +#include @@ -69,6 +78,8 @@ enum LINE_CAP_END = 2 }; +std::locale const f_portable_locale("C"); + //************************************************************************** @@ -129,255 +140,729 @@ inline void render_bounds_transform(render_bounds &bounds, render_bounds const & class layout_syntax_error : public std::invalid_argument { using std::invalid_argument::invalid_argument; }; class layout_reference_error : public std::out_of_range { using std::out_of_range::out_of_range; }; - - -//************************************************************************** -// SHARED PARSING HELPERS -//************************************************************************** - -//------------------------------------------------- -// get_variable_value - compute the value of -// a variable in an XML attribute -//------------------------------------------------- - -int get_variable_value(running_machine &machine, const char *string, char **outputptr) -{ - char temp[100]; - - // screen 0 parameters - int scrnum = 0; - for (const screen_device &device : screen_device_iterator(machine.root_device())) - { - // native X aspect factor - sprintf(temp, "~scr%dnativexaspect~", scrnum); - if (!strncmp(string, temp, strlen(temp))) - { - int num = device.visible_area().width(); - int den = device.visible_area().height(); - reduce_fraction(num, den); - *outputptr += sprintf(*outputptr, "%d", num); - return strlen(temp); - } - - // native Y aspect factor - sprintf(temp, "~scr%dnativeyaspect~", scrnum); - if (!strncmp(string, temp, strlen(temp))) - { - int num = device.visible_area().width(); - int den = device.visible_area().height(); - reduce_fraction(num, den); - *outputptr += sprintf(*outputptr, "%d", den); - return strlen(temp); - } - - // native width - sprintf(temp, "~scr%dwidth~", scrnum); - if (!strncmp(string, temp, strlen(temp))) - { - *outputptr += sprintf(*outputptr, "%d", device.visible_area().width()); - return strlen(temp); - } - - // native height - sprintf(temp, "~scr%dheight~", scrnum); - if (!strncmp(string, temp, strlen(temp))) - { - *outputptr += sprintf(*outputptr, "%d", device.visible_area().height()); - return strlen(temp); - } - - // keep count - scrnum++; - } - - // default: copy the first character and continue - **outputptr = *string; - *outputptr += 1; - return 1; -} - - -//------------------------------------------------- -// xml_get_attribute_string_with_subst - analog -// to xml_get_attribute_string but with variable -// substitution -//------------------------------------------------- - -const char *xml_get_attribute_string_with_subst(running_machine &machine, util::xml::data_node const &node, const char *attribute, const char *defvalue) -{ - const char *str = node.get_attribute_string(attribute, nullptr); - static char buffer[1000]; - - // if nothing, just return the default - if (str == nullptr) - return defvalue; - - // if no tildes, don't worry - if (strchr(str, '~') == nullptr) - return str; - - // make a copy of the string, doing substitutions along the way - const char *s; - char *d; - for (s = str, d = buffer; *s != 0; ) - { - // if not a variable, just copy - if (*s != '~') - *d++ = *s++; - - // extract the variable - else - s += get_variable_value(machine, s, &d); - } - *d = 0; - return buffer; -} - - -//------------------------------------------------- -// xml_get_attribute_int_with_subst - analog -// to xml_get_attribute_int but with variable -// substitution -//------------------------------------------------- - -int xml_get_attribute_int_with_subst(running_machine &machine, util::xml::data_node const &node, const char *attribute, int defvalue) -{ - const char *string = xml_get_attribute_string_with_subst(machine, node, attribute, nullptr); - int value; - unsigned int uvalue; - - if (string == nullptr) - return defvalue; - if (string[0] == '$') - return (sscanf(&string[1], "%X", &uvalue) == 1) ? uvalue : defvalue; - if (string[0] == '0' && string[1] == 'x') - return (sscanf(&string[2], "%X", &uvalue) == 1) ? uvalue : defvalue; - if (string[0] == '#') - return (sscanf(&string[1], "%d", &value) == 1) ? value : defvalue; - return (sscanf(&string[0], "%d", &value) == 1) ? value : defvalue; -} - - -//------------------------------------------------- -// xml_get_attribute_float_with_subst - analog -// to xml_get_attribute_float but with variable -// substitution -//------------------------------------------------- - -float xml_get_attribute_float_with_subst(running_machine &machine, util::xml::data_node const &node, const char *attribute, float defvalue) -{ - const char *string = xml_get_attribute_string_with_subst(machine, node, attribute, nullptr); - float value; - - if (string == nullptr || sscanf(string, "%f", &value) != 1) - return defvalue; - return value; -} - - -//------------------------------------------------- -// parse_bounds - parse a bounds XML node -//------------------------------------------------- - -void parse_bounds(running_machine &machine, util::xml::data_node const *boundsnode, render_bounds &bounds) -{ - // skip if nothing - if (boundsnode == nullptr) - { - bounds.x0 = bounds.y0 = 0.0f; - bounds.x1 = bounds.y1 = 1.0f; - return; - } - - // parse out the data - if (boundsnode->has_attribute("left")) - { - // left/right/top/bottom format - bounds.x0 = xml_get_attribute_float_with_subst(machine, *boundsnode, "left", 0.0f); - bounds.x1 = xml_get_attribute_float_with_subst(machine, *boundsnode, "right", 1.0f); - bounds.y0 = xml_get_attribute_float_with_subst(machine, *boundsnode, "top", 0.0f); - bounds.y1 = xml_get_attribute_float_with_subst(machine, *boundsnode, "bottom", 1.0f); - } - else if (boundsnode->has_attribute("x")) - { - // x/y/width/height format - bounds.x0 = xml_get_attribute_float_with_subst(machine, *boundsnode, "x", 0.0f); - bounds.x1 = bounds.x0 + xml_get_attribute_float_with_subst(machine, *boundsnode, "width", 1.0f); - bounds.y0 = xml_get_attribute_float_with_subst(machine, *boundsnode, "y", 0.0f); - bounds.y1 = bounds.y0 + xml_get_attribute_float_with_subst(machine, *boundsnode, "height", 1.0f); - } - else - { - throw layout_syntax_error("bounds element requires either left or x attribute"); - } - - // check for errors - if ((bounds.x0 > bounds.x1) || (bounds.y0 > bounds.y1)) - throw layout_syntax_error(util::string_format("illegal bounds (%f-%f)-(%f-%f)", bounds.x0, bounds.x1, bounds.y0, bounds.y1)); -} - - -//------------------------------------------------- -// parse_color - parse a color XML node -//------------------------------------------------- - -void parse_color(running_machine &machine, util::xml::data_node const *colornode, render_color &color) -{ - // skip if nothing - if (colornode == nullptr) - { - color.r = color.g = color.b = color.a = 1.0f; - return; - } - - // parse out the data - color.r = xml_get_attribute_float_with_subst(machine, *colornode, "red", 1.0); - color.g = xml_get_attribute_float_with_subst(machine, *colornode, "green", 1.0); - color.b = xml_get_attribute_float_with_subst(machine, *colornode, "blue", 1.0); - color.a = xml_get_attribute_float_with_subst(machine, *colornode, "alpha", 1.0); - - // check for errors - if ((color.r < 0.0f) || (color.r > 1.0f) || (color.g < 0.0f) || (color.g > 1.0f) || - (color.b < 0.0f) || (color.b > 1.0f) || (color.a < 0.0f) || (color.a > 1.0f)) - throw layout_syntax_error(util::string_format("illegal RGBA color %f,%f,%f,%f", color.r, color.g, color.b, color.a)); -} - - -//------------------------------------------------- -// parse_orientation - parse an orientation XML -// node -//------------------------------------------------- - -void parse_orientation(running_machine &machine, util::xml::data_node const *orientnode, int &orientation) -{ - // skip if nothing - if (orientnode == nullptr) - { - orientation = ROT0; - return; - } - - // parse out the data - int rotate = xml_get_attribute_int_with_subst(machine, *orientnode, "rotate", 0); - switch (rotate) - { - case 0: orientation = ROT0; break; - case 90: orientation = ROT90; break; - case 180: orientation = ROT180; break; - case 270: orientation = ROT270; break; - default: throw layout_syntax_error(util::string_format("invalid rotate attribute %d", rotate)); - } - if (strcmp("yes", xml_get_attribute_string_with_subst(machine, *orientnode, "swapxy", "no")) == 0) - orientation ^= ORIENTATION_SWAP_XY; - if (strcmp("yes", xml_get_attribute_string_with_subst(machine, *orientnode, "flipx", "no")) == 0) - orientation ^= ORIENTATION_FLIP_X; - if (strcmp("yes", xml_get_attribute_string_with_subst(machine, *orientnode, "flipy", "no")) == 0) - orientation ^= ORIENTATION_FLIP_Y; -} - } // anonymous namespace +namespace emu { namespace render { namespace detail { + +class layout_environment +{ +private: + class entry + { + public: + entry(std::string &&name, std::string &&t) + : m_name(std::move(name)) + , m_text(std::move(t)) + , m_text_valid(true) + { } + entry(std::string &&name, s64 i) + : m_name(std::move(name)) + , m_int(i) + , m_int_valid(true) + { } + entry(std::string &&name, double f) + : m_name(std::move(name)) + , m_float(f) + , m_float_valid(true) + { } + entry(std::string &&name, std::string &&t, s64 i, int s) + : m_name(std::move(name)) + , m_text(std::move(t)) + , m_int_increment(i) + , m_shift(s) + , m_text_valid(true) + , m_incrementing(true) + { } + entry(std::string &&name, std::string &&t, double i, int s) + : m_name(std::move(name)) + , m_text(std::move(t)) + , m_float_increment(i) + , m_shift(s) + , m_text_valid(true) + , m_incrementing(true) + { } + entry(entry &&) = default; + entry &operator=(entry &&) = default; + + void set(std::string &&t) + { + m_text = std::move(t); + m_text_valid = true; + m_int_valid = false; + m_float_valid = false; + } + void set(s64 i) + { + m_int = i; + m_text_valid = false; + m_int_valid = true; + m_float_valid = false; + } + void set(double f) + { + m_float = f; + m_text_valid = false; + m_int_valid = false; + m_float_valid = true; + } + + std::string const &name() const { return m_name; } + bool is_incrementing() const { return m_incrementing; } + + std::string const &get_text() + { + if (!m_text_valid) + { + if (m_float_valid) + { + m_text = std::to_string(m_float); + m_text_valid = true; + } + else if (m_int_valid) + { + m_text = std::to_string(m_int); + m_text_valid = true; + } + } + return m_text; + } + + void increment() + { + if (is_incrementing()) + { + // apply increment + if (m_float_increment) + { + if (m_int_valid && !m_float_valid) + { + m_float = m_int; + m_float_valid = true; + } + if (m_text_valid && !m_float_valid) + { + std::istringstream stream(m_text); + stream.imbue(f_portable_locale); + m_text.c_str(); + if (m_text[0] == '$') + { + stream.get(); + u64 uvalue; + stream >> std::hex >> uvalue; + m_float = uvalue; + } + else if ((m_text[0] == '0') && ((m_text[1] == 'x') || (m_text[1] == 'X'))) + { + stream.get(); + stream.get(); + u64 uvalue; + stream >> std::hex >> uvalue; + m_float = uvalue; + } + else if (m_text[0] == '#') + { + stream.get(); + stream >> m_int; + m_float = m_int; + } + else + { + stream >> m_float; + } + m_float_valid = bool(stream); + } + m_float += m_float_increment; + m_int_valid = m_text_valid = false; + } + else + { + if (m_text_valid && !m_int_valid && !m_float_valid) + { + std::istringstream stream(m_text); + stream.imbue(f_portable_locale); + m_text.c_str(); + if (m_text[0] == '$') + { + stream.get(); + u64 uvalue; + stream >> std::hex >> uvalue; + m_int = s64(uvalue); + m_int_valid = bool(stream); + } + else if ((m_text[0] == '0') && ((m_text[1] == 'x') || (m_text[1] == 'X'))) + { + stream.get(); + stream.get(); + u64 uvalue; + stream >> std::hex >> uvalue; + m_int = s64(uvalue); + m_int_valid = bool(stream); + } + else if (m_text[0] == '#') + { + stream.get(); + stream >> m_int; + m_int_valid = bool(stream); + } + else if (m_text.find_first_of(".eE") != std::string::npos) + { + stream >> m_float; + m_float_valid = bool(stream); + } + else + { + stream >> m_int; + m_int_valid = bool(stream); + } + } + + if (m_float_valid) + { + m_float += m_int_increment; + m_int_valid = m_text_valid = false; + } + else + { + m_int += m_int_increment; + m_float_valid = m_text_valid = false; + } + } + + // apply shift + if (m_shift) + { + if (m_float_valid && !m_int_valid) + { + m_int = s64(m_float); + m_int_valid = true; + } + if (m_text_valid && !m_int_valid) + { + std::istringstream stream(m_text); + stream.imbue(f_portable_locale); + m_text.c_str(); + if (m_text[0] == '$') + { + stream.get(); + u64 uvalue; + stream >> std::hex >> uvalue; + m_int = s64(uvalue); + } + else if ((m_text[0] == '0') && ((m_text[1] == 'x') || (m_text[1] == 'X'))) + { + stream.get(); + stream.get(); + u64 uvalue; + stream >> std::hex >> uvalue; + m_int = s64(uvalue); + } + else + { + if (m_text[0] == '#') + stream.get(); + stream >> m_int; + } + m_int_valid = bool(stream); + } + if (0 > m_shift) + m_int >>= -m_shift; + else + m_int <<= m_shift; + m_text_valid = m_float_valid = false; + } + } + } + + static bool name_less(entry const &lhs, entry const &rhs) { return lhs.name() < rhs.name(); } + + private: + std::string m_name; + std::string m_text; + s64 m_int = 0, m_int_increment = 0; + double m_float = 0.0, m_float_increment = 0.0; + int m_shift = 0; + bool m_text_valid = false; + bool m_int_valid = false; + bool m_float_valid = false; + bool m_incrementing = false; + }; + + using entry_vector = std::vector; + + template + void try_insert(T &&name, U &&value) + { + entry_vector::iterator const pos( + std::lower_bound( + m_entries.begin(), + m_entries.end(), + name, + [] (entry const &lhs, auto const &rhs) { return lhs.name() < rhs; })); + if ((m_entries.end() == pos) || (pos->name() != name)) + m_entries.emplace(pos, std::forward(name), std::forward(value)); + } + + template + void set(T &&name, U &&value) + { + entry_vector::iterator const pos( + std::lower_bound( + m_entries.begin(), + m_entries.end(), + name, + [] (entry const &lhs, auto const &rhs) { return lhs.name() < rhs; })); + if ((m_entries.end() == pos) || (pos->name() != name)) + m_entries.emplace(pos, std::forward(name), std::forward(value)); + else + pos->set(std::forward(value)); + } + + void cache_device_entries() + { + if (!m_next && !m_cached) + { + try_insert("devicetag", device().tag()); + try_insert("devicebasetag", device().basetag()); + try_insert("devicename", device().name()); + try_insert("deviceshortname", device().shortname()); + util::ovectorstream tmp; + unsigned i(0U); + for (screen_device const &screen : screen_device_iterator(machine().root_device())) + { + s64 const w(screen.visible_area().width()), h(screen.visible_area().height()); + s64 xaspect(w), yaspect(h); + reduce_fraction(xaspect, yaspect); + + tmp.seekp(0); + util::stream_format(tmp, "scr%unativexaspect", i); + tmp.put('\0'); + try_insert(&tmp.vec()[0], xaspect); + + tmp.seekp(0); + util::stream_format(tmp, "scr%unativeyaspect", i); + tmp.put('\0'); + try_insert(&tmp.vec()[0], yaspect); + + tmp.seekp(0); + util::stream_format(tmp, "scr%uwidth", i); + tmp.put('\0'); + try_insert(&tmp.vec()[0], w); + + tmp.seekp(0); + util::stream_format(tmp, "scr%uheight", i); + tmp.put('\0'); + try_insert(&tmp.vec()[0], h); + + ++i; + } + m_cached = true; + } + } + + entry *find_entry(char const *begin, char const *end) + { + cache_device_entries(); + entry_vector::iterator const pos( + std::lower_bound( + m_entries.begin(), + m_entries.end(), + std::make_pair(begin, end - begin), + [] (entry const &lhs, std::pair const &rhs) + { return 0 > std::strncmp(lhs.name().c_str(), rhs.first, rhs.second); })); + if ((m_entries.end() != pos) && (pos->name().length() == (end - begin)) && !std::strncmp(pos->name().c_str(), begin, end - begin)) + return &*pos; + else + return m_next ? m_next->find_entry(begin, end) : nullptr; + } + + template + std::tuple get_variable_text(T &&... args) + { + entry *const found(find_entry(std::forward(args)...)); + if (found) + { + std::string const &text(found->get_text()); + char const *const begin(text.c_str()); + return std::make_tuple(begin, begin + text.length(), true); + } + else + { + return std::make_tuple(nullptr, nullptr, false); + } + } + + std::pair expand(char const *begin, char const *end) + { + // search for candidate variable references + char const *start(begin); + char const *pos(std::find_if(start, end, is_variable_start)); + while (pos != end) + { + char const *const term(std::find_if(pos + 1, end, [] (char ch) { return !is_variable_char(ch); })); + if ((term == end) || !is_variable_end(*term)) + { + // not a valid variable name - keep searching + pos = std::find_if(term, end, is_variable_start); + } + else + { + // looks like a variable reference - try to look it up + std::tuple const text(get_variable_text(pos + 1, term)); + if (std::get<2>(text)) + { + // variable found + if (begin == start) + m_buffer.seekp(0); + m_buffer.write(start, pos - start); + m_buffer.write(std::get<0>(text), std::get<1>(text) - std::get<0>(text)); + start = term + 1; + pos = std::find_if(start, end, is_variable_start); + } + else + { + // variable not found - move on + pos = std::find_if(pos + 1, end, is_variable_start); + } + } + } + + // short-circuit the case where no substitutions were made + if (start == begin) + { + return std::make_pair(begin, end); + } + else + { + m_buffer.write(start, pos - start); + m_buffer.put('\0'); + std::vector const &vec(m_buffer.vec()); + if (vec.empty()) + return std::make_pair(nullptr, nullptr); + else + return std::make_pair(&vec[0], &vec[0] + vec.size() - 1); + } + } + + std::pair expand(char const *str) + { + return expand(str, str + strlen(str)); + } + + std::string parameter_name(util::xml::data_node const &node) + { + char const *const attrib(node.get_attribute_string("name", nullptr)); + if (!attrib) + throw layout_syntax_error("parameter lacks name attribute"); + std::pair const expanded(expand(attrib)); + return std::string(expanded.first, expanded.second); + } + + static constexpr bool is_variable_start(char ch) + { + return '~' == ch; + } + static constexpr bool is_variable_end(char ch) + { + return '~' == ch; + } + static constexpr bool is_variable_char(char ch) + { + return (('0' <= ch) && ('9' >= ch)) || (('A' <= ch) && ('Z' >= ch)) || (('a' <= ch) && ('z' >= ch)) || ('_' == ch); + } + + entry_vector m_entries; + util::ovectorstream m_buffer; + device_t &m_device; + layout_environment *const m_next = nullptr; + bool m_cached = false; + +public: + explicit layout_environment(device_t &device) : m_device(device) { } + explicit layout_environment(layout_environment &next) : m_device(next.m_device), m_next(&next) { } + layout_environment(layout_environment const &) = delete; + + device_t &device() { return m_device; } + running_machine &machine() { return device().machine(); } + bool is_root_device() { return &device() == &machine().root_device(); } + + void set_parameter(std::string &&name, std::string &&value) + { + set(std::move(name), std::move(value)); + } + + void set_parameter(std::string &&name, s64 value) + { + set(std::move(name), value); + } + + void set_parameter(std::string &&name, double value) + { + set(std::move(name), value); + } + + void set_parameter(util::xml::data_node const &node) + { + // do basic validation + std::string name(parameter_name(node)); + if (node.has_attribute("start") || node.has_attribute("increment") || node.has_attribute("lshift") || node.has_attribute("rshift")) + throw layout_syntax_error("start/increment/lshift/rshift attributes are only allowed for repeat parameters"); + char const *const value(node.get_attribute_string("value", nullptr)); + if (!value) + throw layout_syntax_error("parameter lacks value attribute"); + + // expand value and stash + std::pair const expanded(expand(value)); + set(std::move(name), std::string(expanded.first, expanded.second)); + } + + void set_repeat_parameter(util::xml::data_node const &node, bool init) + { + // two types are allowed here - static value, and start/increment/lshift/rshift + std::string name(parameter_name(node)); + char const *const start(node.get_attribute_string("start", nullptr)); + if (start) + { + // simple validity checks + if (node.has_attribute("value")) + throw layout_syntax_error("start attribute may not be used in combination with value attribute"); + int const lshift(node.has_attribute("lshift") ? get_attribute_int(node, "lshift", -1) : 0); + int const rshift(node.has_attribute("rshift") ? get_attribute_int(node, "rshift", -1) : 0); + if ((0 > lshift) || (0 > rshift)) + throw layout_syntax_error("lshift/rshift attributes must be non-negative integers"); + + // increment is more complex - it may be an integer or a floating-point number + s64 intincrement(0); + double floatincrement(0); + char const *const increment(node.get_attribute_string("increment", nullptr)); + if (increment) + { + std::pair const expanded(expand(increment)); + unsigned const hexprefix((expanded.first[0] == '$') ? 1U : ((expanded.first[0] == '0') && ((expanded.first[1] == 'x') || (expanded.first[1] == 'X'))) ? 2U : 0U); + unsigned const decprefix((expanded.first[0] == '#') ? 1U : 0U); + bool const floatchars(std::find_if(expanded.first, expanded.second, [] (char ch) { return ('.' == ch) || ('e' == ch) || ('E' == ch); }) != expanded.second); + std::istringstream stream(std::string(expanded.first + hexprefix + decprefix, expanded.second)); + stream.imbue(f_portable_locale); + if (!hexprefix && !decprefix && floatchars) + { + stream >> floatincrement; + } + else if (hexprefix) + { + u64 uvalue; + stream >> std::hex >> uvalue; + intincrement = s64(uvalue); + } + else + { + stream >> intincrement; + } + + // reject obviously bad stuff + if (!stream) + throw layout_syntax_error("increment attribute must be a number"); + } + + // don't allow incrementing parameters to be redefined + if (init) + { + entry_vector::iterator const pos( + std::lower_bound( + m_entries.begin(), + m_entries.end(), + name, + [] (entry const &lhs, auto const &rhs) { return lhs.name() < rhs; })); + if ((m_entries.end() != pos) && (pos->name() == name)) + throw layout_syntax_error("incrementing parameters must be defined exactly once per scope"); + + std::pair const expanded(expand(start)); + if (floatincrement) + m_entries.emplace(pos, std::move(name), std::string(expanded.first, expanded.second), floatincrement, lshift - rshift); + else + m_entries.emplace(pos, std::move(name), std::string(expanded.first, expanded.second), intincrement, lshift - rshift); + } + } + else if (node.has_attribute("increment") || node.has_attribute("lshift") || node.has_attribute("rshift")) + { + throw layout_syntax_error("increment/lshift/rshift attributes require start attribute"); + } + else + { + char const *const value(node.get_attribute_string("value", nullptr)); + if (!value) + throw layout_syntax_error("parameter lacks value attribute"); + std::pair const expanded(expand(value)); + entry_vector::iterator const pos( + std::lower_bound( + m_entries.begin(), + m_entries.end(), + name, + [] (entry const &lhs, auto const &rhs) { return lhs.name() < rhs; })); + if ((m_entries.end() == pos) || (pos->name() != name)) + m_entries.emplace(pos, std::move(name), std::string(expanded.first, expanded.second)); + else if (pos->is_incrementing()) + throw layout_syntax_error("incrementing parameters must be defined exactly once per scope"); + else + pos->set(std::string(expanded.first, expanded.second)); + } + } + + void increment_parameters() + { + for (entry &e : m_entries) + e.increment(); + } + + char const *get_attribute_string(util::xml::data_node const &node, char const *name, char const *defvalue) + { + char const *const attrib(node.get_attribute_string(name, nullptr)); + return attrib ? expand(attrib).first : defvalue; + } + + int get_attribute_int(util::xml::data_node const &node, const char *name, int defvalue) + { + char const *const attrib(node.get_attribute_string(name, nullptr)); + if (!attrib) + return defvalue; + + // similar to what XML nodes do + std::pair const expanded(expand(attrib)); + std::istringstream stream; + stream.imbue(f_portable_locale); + int result; + if (expanded.first[0] == '$') + { + stream.str(std::string(expanded.first + 1, expanded.second)); + unsigned uvalue; + stream >> std::hex >> uvalue; + result = int(uvalue); + } + else if ((expanded.first[0] == '0') && ((expanded.first[1] == 'x') || (expanded.first[1] == 'X'))) + { + stream.str(std::string(expanded.first + 2, expanded.second)); + unsigned uvalue; + stream >> std::hex >> uvalue; + result = int(uvalue); + } + else if (expanded.first[0] == '#') + { + stream.str(std::string(expanded.first + 1, expanded.second)); + stream >> result; + } + else + { + stream.str(std::string(expanded.first, expanded.second)); + stream >> result; + } + + return stream ? result : defvalue; + } + + float get_attribute_float(util::xml::data_node const &node, char const *name, float defvalue) + { + char const *const attrib(node.get_attribute_string(name, nullptr)); + if (!attrib) + return defvalue; + + // similar to what XML nodes do + std::pair const expanded(expand(attrib)); + std::istringstream stream(std::string(expanded.first, expanded.second)); + stream.imbue(f_portable_locale); + float result; + return (stream >> result) ? result : defvalue; + } + + void parse_bounds(util::xml::data_node const *node, render_bounds &result) + { + // default to unit rectangle + if (!node) + { + result.x0 = result.y0 = 0.0F; + result.x1 = result.y1 = 1.0F; + } + else + { + // parse attributes + if (node->has_attribute("left")) + { + // left/right/top/bottom format + result.x0 = get_attribute_float(*node, "left", 0.0F); + result.x1 = get_attribute_float(*node, "right", 1.0F); + result.y0 = get_attribute_float(*node, "top", 0.0F); + result.y1 = get_attribute_float(*node, "bottom", 1.0F); + } + else if (node->has_attribute("x")) + { + // x/y/width/height format + result.x0 = get_attribute_float(*node, "x", 0.0F); + result.x1 = result.x0 + get_attribute_float(*node, "width", 1.0F); + result.y0 = get_attribute_float(*node, "y", 0.0F); + result.y1 = result.y0 + get_attribute_float(*node, "height", 1.0F); + } + else + { + throw layout_syntax_error("bounds element requires either left or x attribute"); + } + + // check for errors + if ((result.x0 > result.x1) || (result.y0 > result.y1)) + throw layout_syntax_error(util::string_format("illegal bounds (%f-%f)-(%f-%f)", result.x0, result.x1, result.y0, result.y1)); + } + } + + void parse_color(util::xml::data_node const *node, render_color &result) + { + // default to white + if (!node) + { + result.r = result.g = result.b = result.a = 1.0F; + } + else + { + // parse attributes + result.r = get_attribute_float(*node, "red", 1.0F); + result.g = get_attribute_float(*node, "green", 1.0F); + result.b = get_attribute_float(*node, "blue", 1.0F); + result.a = get_attribute_float(*node, "alpha", 1.0F); + + // check for errors + if ((0.0F > (std::min)({ result.r, result.g, result.b, result.a })) || (1.0F < (std::max)({ result.r, result.g, result.b, result.a }))) + throw layout_syntax_error(util::string_format("illegal RGBA color %f,%f,%f,%f", result.r, result.g, result.b, result.a)); + } + } + + void parse_orientation(util::xml::data_node const *node, int &result) + { + // default to no transform + if (!node) + { + result = ROT0; + } + else + { + // parse attributes + int const rotate(get_attribute_int(*node, "rotate", 0)); + switch (rotate) + { + case 0: result = ROT0; break; + case 90: result = ROT90; break; + case 180: result = ROT180; break; + case 270: result = ROT270; break; + default: throw layout_syntax_error(util::string_format("invalid rotate attribute %d", rotate)); + } + if (!std::strcmp("yes", get_attribute_string(*node, "swapxy", "no"))) + result ^= ORIENTATION_SWAP_XY; + if (!std::strcmp("yes", get_attribute_string(*node, "flipx", "no"))) + result ^= ORIENTATION_FLIP_X; + if (!std::strcmp("yes", get_attribute_string(*node, "flipy", "no"))) + result ^= ORIENTATION_FLIP_Y; + } + } +}; + +} } } // namespace emu::render::detail + + //************************************************************************** // GLOBAL VARIABLES @@ -413,13 +898,13 @@ layout_element::make_component_map const layout_element::s_make_component{ // layout_element - constructor //------------------------------------------------- -layout_element::layout_element(running_machine &machine, util::xml::data_node const &elemnode, const char *dirname) - : m_machine(machine) +layout_element::layout_element(environment &env, util::xml::data_node const &elemnode, const char *dirname) + : m_machine(env.machine()) , m_defstate(0) , m_maxstate(0) { // get the default state - m_defstate = xml_get_attribute_int_with_subst(machine, elemnode, "defstate", -1); + m_defstate = env.get_attribute_int(elemnode, "defstate", -1); // parse components in order bool first = true; @@ -431,7 +916,7 @@ layout_element::layout_element(running_machine &machine, util::xml::data_node co throw layout_syntax_error(util::string_format("unknown element component %s", compnode->get_name())); // insert the new component into the list - component const &newcomp(**m_complist.emplace(m_complist.end(), make_func->second(machine, *compnode, dirname))); + component const &newcomp(**m_complist.emplace(m_complist.end(), make_func->second(env, *compnode, dirname))); // accumulate bounds if (first) @@ -480,9 +965,8 @@ layout_element::~layout_element() // layout_group - constructor //------------------------------------------------- -layout_group::layout_group(running_machine &machine, util::xml::data_node const &groupnode) - : m_machine(machine) - , m_groupnode(groupnode) +layout_group::layout_group(util::xml::data_node const &groupnode) + : m_groupnode(groupnode) , m_bounds{ 0.0f, 0.0f, 0.0f, 0.0f } , m_bounds_resolved(false) { @@ -530,16 +1014,21 @@ render_bounds layout_group::make_transform(render_bounds const &dest, render_bou // nested groups into consideration //------------------------------------------------- -void layout_group::resolve_bounds(group_map &groupmap) +void layout_group::set_bounds_unresolved() +{ + m_bounds_resolved = false; +} + +void layout_group::resolve_bounds(environment &env, group_map &groupmap) { if (!m_bounds_resolved) { std::vector seen; - resolve_bounds(groupmap, seen); + resolve_bounds(env, groupmap, seen); } } -void layout_group::resolve_bounds(group_map &groupmap, std::vector &seen) +void layout_group::resolve_bounds(environment &env, group_map &groupmap, std::vector &seen) { if (seen.end() != std::find(seen.begin(), seen.end(), this)) { @@ -554,59 +1043,87 @@ void layout_group::resolve_bounds(group_map &groupmap, std::vector &seen, + bool repeat, + bool init) +{ + bool envaltered(false); + bool unresolved(true); + for (util::xml::data_node const *itemnode = parentnode.get_first_child(); !m_bounds_resolved && itemnode; itemnode = itemnode->get_next_sibling()) + { + if (!strcmp(itemnode->get_name(), "bounds")) { // use explicit bounds - parse_bounds(m_machine, boundsnode, m_bounds); + env.parse_bounds(itemnode, m_bounds); + m_bounds_resolved = true; + } + else if (!strcmp(itemnode->get_name(), "param")) + { + envaltered = true; + if (!unresolved) + { + unresolved = true; + for (group_map::value_type &group : groupmap) + group.second.set_bounds_unresolved(); + } + if (!repeat) + env.set_parameter(*itemnode); + else + env.set_repeat_parameter(*itemnode, init); + } + else if (!strcmp(itemnode->get_name(), "backdrop") || + !strcmp(itemnode->get_name(), "screen") || + !strcmp(itemnode->get_name(), "overlay") || + !strcmp(itemnode->get_name(), "bezel") || + !strcmp(itemnode->get_name(), "cpanel") || + !strcmp(itemnode->get_name(), "marquee")) + { + render_bounds itembounds; + env.parse_bounds(itemnode->get_child("bounds"), itembounds); + union_render_bounds(m_bounds, itembounds); + } + else if (!strcmp(itemnode->get_name(), "group")) + { + char const *ref(env.get_attribute_string(*itemnode, "ref", nullptr)); + if (!ref) + throw layout_syntax_error("nested group must have ref attribute"); + + group_map::iterator const found(groupmap.find(ref)); + if (groupmap.end() == found) + throw layout_syntax_error(util::string_format("unable to find group %s", ref)); + + environment local(env); + found->second.resolve_bounds(local, groupmap, seen); + union_render_bounds(m_bounds, found->second.m_bounds); + } + else if (!strcmp(itemnode->get_name(), "repeat")) + { + int const count(env.get_attribute_int(*itemnode, "count", -1)); + if (0 >= count) + throw layout_syntax_error("repeat must have positive integer count attribute"); + environment local(env); + for (int i = 0; !m_bounds_resolved && (count > i); ++i) + { + resolve_bounds(local, *itemnode, groupmap, seen, true, !i); + local.increment_parameters(); + } } else { - // otherwise build from items - for (util::xml::data_node const *itemnode = m_groupnode.get_first_child(); itemnode; itemnode = itemnode->get_next_sibling()) - { - if (!strcmp(itemnode->get_name(), "backdrop") || - !strcmp(itemnode->get_name(), "screen") || - !strcmp(itemnode->get_name(), "overlay") || - !strcmp(itemnode->get_name(), "bezel") || - !strcmp(itemnode->get_name(), "cpanel") || - !strcmp(itemnode->get_name(), "marquee")) - { - render_bounds itembounds; - parse_bounds(m_machine, itemnode->get_child("bounds"), itembounds); - union_render_bounds(m_bounds, itembounds); - } - else if (!strcmp(itemnode->get_name(), "group")) - { - char const *ref(xml_get_attribute_string_with_subst(m_machine, *itemnode, "ref", nullptr)); - if (!ref) - throw layout_syntax_error("nested group must have ref attribute"); - - group_map::iterator const found(groupmap.find(ref)); - if (groupmap.end() == found) - throw layout_syntax_error(util::string_format("unable to find group %s", ref)); - - found->second.resolve_bounds(groupmap, seen); - util::xml::data_node const *const itemboundsnode(itemnode->get_child("bounds")); - if (itemboundsnode) - { - render_bounds itembounds; - parse_bounds(m_machine, itemboundsnode, itembounds); - union_render_bounds(m_bounds, itembounds); - } - else - { - union_render_bounds(m_bounds, found->second.m_bounds); - } - } - else if (strcmp(itemnode->get_name(), "bounds")) - { - throw layout_syntax_error(util::string_format("unknown group element %s", itemnode->get_name())); - } - } + throw layout_syntax_error(util::string_format("unknown group element %s", itemnode->get_name())); } - m_bounds_resolved = true; } + if (!repeat) + m_bounds_resolved = true; } @@ -663,15 +1180,15 @@ class layout_element::image_component : public component { public: // construction/destruction - image_component(running_machine &machine, util::xml::data_node const &compnode, const char *dirname) - : component(machine, compnode, dirname) + image_component(environment &env, util::xml::data_node const &compnode, const char *dirname) + : component(env, compnode, dirname) , m_hasalpha(false) { if (dirname != nullptr) m_dirname = dirname; - m_imagefile = xml_get_attribute_string_with_subst(machine, compnode, "file", ""); - m_alphafile = xml_get_attribute_string_with_subst(machine, compnode, "alphafile", ""); - m_file = std::make_unique(machine.options().art_path(), OPEN_FLAG_READ); + m_imagefile = env.get_attribute_string(compnode, "file", ""); + m_alphafile = env.get_attribute_string(compnode, "alphafile", ""); + m_file = std::make_unique(env.machine().options().art_path(), OPEN_FLAG_READ); } protected: @@ -745,8 +1262,8 @@ class layout_element::rect_component : public component { public: // construction/destruction - rect_component(running_machine &machine, util::xml::data_node const &compnode, const char *dirname) - : component(machine, compnode, dirname) + rect_component(environment &env, util::xml::data_node const &compnode, const char *dirname) + : component(env, compnode, dirname) { } @@ -791,8 +1308,8 @@ class layout_element::disk_component : public component { public: // construction/destruction - disk_component(running_machine &machine, util::xml::data_node const &compnode, const char *dirname) - : component(machine, compnode, dirname) + disk_component(environment &env, util::xml::data_node const &compnode, const char *dirname) + : component(env, compnode, dirname) { } @@ -852,11 +1369,11 @@ class layout_element::text_component : public component { public: // construction/destruction - text_component(running_machine &machine, util::xml::data_node const &compnode, const char *dirname) - : component(machine, compnode, dirname) + text_component(environment &env, util::xml::data_node const &compnode, const char *dirname) + : component(env, compnode, dirname) { - m_string = xml_get_attribute_string_with_subst(machine, compnode, "string", ""); - m_textalign = xml_get_attribute_int_with_subst(machine, compnode, "align", 0); + m_string = env.get_attribute_string(compnode, "string", ""); + m_textalign = env.get_attribute_int(compnode, "align", 0); } protected: @@ -880,8 +1397,8 @@ class layout_element::led7seg_component : public component { public: // construction/destruction - led7seg_component(running_machine &machine, util::xml::data_node const &compnode, const char *dirname) - : component(machine, compnode, dirname) + led7seg_component(environment &env, util::xml::data_node const &compnode, const char *dirname) + : component(env, compnode, dirname) { } @@ -942,8 +1459,8 @@ class layout_element::led8seg_gts1_component : public component { public: // construction/destruction - led8seg_gts1_component(running_machine &machine, util::xml::data_node const &compnode, const char *dirname) - : component(machine, compnode, dirname) + led8seg_gts1_component(environment &env, util::xml::data_node const &compnode, const char *dirname) + : component(env, compnode, dirname) { } @@ -1010,8 +1527,8 @@ class layout_element::led14seg_component : public component { public: // construction/destruction - led14seg_component(running_machine &machine, util::xml::data_node const &compnode, const char *dirname) - : component(machine, compnode, dirname) + led14seg_component(environment &env, util::xml::data_node const &compnode, const char *dirname) + : component(env, compnode, dirname) { } @@ -1122,8 +1639,8 @@ class layout_element::led16seg_component : public component { public: // construction/destruction - led16seg_component(running_machine &machine, util::xml::data_node const &compnode, const char *dirname) - : component(machine, compnode, dirname) + led16seg_component(environment &env, util::xml::data_node const &compnode, const char *dirname) + : component(env, compnode, dirname) { } @@ -1244,8 +1761,8 @@ class layout_element::led14segsc_component : public component { public: // construction/destruction - led14segsc_component(running_machine &machine, util::xml::data_node const &compnode, const char *dirname) - : component(machine, compnode, dirname) + led14segsc_component(environment &env, util::xml::data_node const &compnode, const char *dirname) + : component(env, compnode, dirname) { } @@ -1365,8 +1882,8 @@ class layout_element::led16segsc_component : public component { public: // construction/destruction - led16segsc_component(running_machine &machine, util::xml::data_node const &compnode, const char *dirname) - : component(machine, compnode, dirname) + led16segsc_component(environment &env, util::xml::data_node const &compnode, const char *dirname) + : component(env, compnode, dirname) { } @@ -1496,8 +2013,8 @@ class layout_element::dotmatrix_component : public component { public: // construction/destruction - dotmatrix_component(int dots, running_machine &machine, util::xml::data_node const &compnode, const char *dirname) - : component(machine, compnode, dirname) + dotmatrix_component(int dots, environment &env, util::xml::data_node const &compnode, const char *dirname) + : component(env, compnode, dirname) , m_dots(dots) { } @@ -1537,11 +2054,11 @@ class layout_element::simplecounter_component : public component { public: // construction/destruction - simplecounter_component(running_machine &machine, util::xml::data_node const &compnode, const char *dirname) - : component(machine, compnode, dirname) - , m_digits(xml_get_attribute_int_with_subst(machine, compnode, "digits", 2)) - , m_textalign(xml_get_attribute_int_with_subst(machine, compnode, "align", 0)) - , m_maxstate(xml_get_attribute_int_with_subst(machine, compnode, "maxstate", 999)) + simplecounter_component(environment &env, util::xml::data_node const &compnode, const char *dirname) + : component(env, compnode, dirname) + , m_digits(env.get_attribute_int(compnode, "digits", 2)) + , m_textalign(env.get_attribute_int(compnode, "align", 0)) + , m_maxstate(env.get_attribute_int(compnode, "maxstate", 999)) { } @@ -1572,13 +2089,13 @@ class layout_element::reel_component : public component public: // construction/destruction - reel_component(running_machine &machine, util::xml::data_node const &compnode, const char *dirname) - : component(machine, compnode, dirname) + reel_component(environment &env, util::xml::data_node const &compnode, const char *dirname) + : component(env, compnode, dirname) { for (auto & elem : m_hasalpha) elem = false; - std::string symbollist = xml_get_attribute_string_with_subst(machine, compnode, "symbollist", "0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15"); + std::string symbollist = env.get_attribute_string(compnode, "symbollist", "0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15"); // split out position names from string and figure out our number of symbols int location; @@ -1608,7 +2125,7 @@ public: m_imagefile[i] = m_imagefile[i].substr(location+1, m_imagefile[i].length()-(location-1)); //m_alphafile[i] = - m_file[i] = std::make_unique(machine.options().art_path(), OPEN_FLAG_READ); + m_file[i] = std::make_unique(env.machine().options().art_path(), OPEN_FLAG_READ); } else { @@ -1618,10 +2135,10 @@ public: } } - m_stateoffset = xml_get_attribute_int_with_subst(machine, compnode, "stateoffset", 0); - m_numsymbolsvisible = xml_get_attribute_int_with_subst(machine, compnode, "numsymbolsvisible", 3); - m_reelreversed = xml_get_attribute_int_with_subst(machine, compnode, "reelreversed", 0); - m_beltreel = xml_get_attribute_int_with_subst(machine, compnode, "beltreel", 0); + m_stateoffset = env.get_attribute_int(compnode, "stateoffset", 0); + m_numsymbolsvisible = env.get_attribute_int(compnode, "numsymbolsvisible", 3); + m_reelreversed = env.get_attribute_int(compnode, "reelreversed", 0); + m_beltreel = env.get_attribute_int(compnode, "beltreel", 0); } protected: @@ -1631,7 +2148,7 @@ protected: { if (m_beltreel) { - draw_beltreel(machine,dest,bounds,state); + draw_beltreel(machine, dest, bounds, state); return; } @@ -1996,9 +2513,9 @@ private: //------------------------------------------------- template -layout_element::component::ptr layout_element::make_component(running_machine &machine, util::xml::data_node const &compnode, const char *dirname) +layout_element::component::ptr layout_element::make_component(environment &env, util::xml::data_node const &compnode, const char *dirname) { - return std::make_unique(machine, compnode, dirname); + return std::make_unique(env, compnode, dirname); } @@ -2008,9 +2525,9 @@ layout_element::component::ptr layout_element::make_component(running_machine &m //------------------------------------------------- template -layout_element::component::ptr layout_element::make_dotmatrix_component(running_machine &machine, util::xml::data_node const &compnode, const char *dirname) +layout_element::component::ptr layout_element::make_dotmatrix_component(environment &env, util::xml::data_node const &compnode, const char *dirname) { - return std::make_unique(D, machine, compnode, dirname); + return std::make_unique(D, env, compnode, dirname); } @@ -2071,13 +2588,13 @@ layout_element::texture &layout_element::texture::operator=(texture &&that) // component - constructor //------------------------------------------------- -layout_element::component::component(running_machine &machine, util::xml::data_node const &compnode, const char *dirname) +layout_element::component::component(environment &env, util::xml::data_node const &compnode, const char *dirname) : m_state(0) { // fetch common data - m_state = xml_get_attribute_int_with_subst(machine, compnode, "state", -1); - parse_bounds(machine, compnode.get_child("bounds"), m_bounds); - parse_color(machine, compnode.get_child("color"), m_color); + m_state = env.get_attribute_int(compnode, "state", -1); + env.parse_bounds(compnode.get_child("bounds"), m_bounds); + env.parse_color(compnode.get_child("color"), m_color); } @@ -2389,25 +2906,21 @@ void layout_element::component::apply_skew(bitmap_argb32 &dest, int skewwidth) //------------------------------------------------- layout_view::layout_view( - device_t &device, + environment &env, util::xml::data_node const &viewnode, element_map &elemmap, - group_map const &groupmap) - : m_name(make_name(device, viewnode)) + group_map &groupmap) + : m_name(make_name(env, viewnode)) , m_aspect(1.0f) , m_scraspect(1.0f) { - // if we have a bounds item, load it - util::xml::data_node const *const boundsnode = viewnode.get_child("bounds"); m_expbounds.x0 = m_expbounds.y0 = m_expbounds.x1 = m_expbounds.y1 = 0; - if (boundsnode) - parse_bounds(device.machine(), boundsnode, m_expbounds); - - // load items - add_items(device, viewnode, elemmap, groupmap, render_bounds{ 0.0f, 0.0f, 1.0f, 1.0f }); - - // recompute the data for the view based on a default layer config + environment local(env); + local.set_parameter("viewname", std::string(m_name)); + add_items(local, viewnode, elemmap, groupmap, render_bounds{ 0.0f, 0.0f, 1.0f, 1.0f }, true, false, true); recompute(render_layer_config()); + for (group_map::value_type &group : groupmap) + group.second.set_bounds_unresolved(); } @@ -2561,76 +3074,125 @@ void layout_view::resolve_tags() //------------------------------------------------- void layout_view::add_items( - device_t &device, + environment &env, util::xml::data_node const &parentnode, element_map &elemmap, - group_map const &groupmap, - render_bounds const &transform) + group_map &groupmap, + render_bounds const &transform, + bool root, + bool repeat, + bool init) { + bool envaltered(false); + bool unresolved(true); for (util::xml::data_node const *itemnode = parentnode.get_first_child(); itemnode; itemnode = itemnode->get_next_sibling()) { - if (!strcmp(itemnode->get_name(), "backdrop")) + if (!strcmp(itemnode->get_name(), "bounds")) { - m_backdrop_list.emplace_back(device, *itemnode, elemmap, transform); + // set explicit bounds + if (root) + env.parse_bounds(itemnode, m_expbounds); + } + else if (!strcmp(itemnode->get_name(), "param")) + { + envaltered = true; + if (!unresolved) + { + unresolved = true; + for (group_map::value_type &group : groupmap) + group.second.set_bounds_unresolved(); + } + if (!repeat) + env.set_parameter(*itemnode); + else + env.set_repeat_parameter(*itemnode, init); + } + else if (!strcmp(itemnode->get_name(), "backdrop")) + { + m_backdrop_list.emplace_back(env, *itemnode, elemmap, transform); } else if (!strcmp(itemnode->get_name(), "screen")) { - m_screen_list.emplace_back(device, *itemnode, elemmap, transform); + m_screen_list.emplace_back(env, *itemnode, elemmap, transform); } else if (!strcmp(itemnode->get_name(), "overlay")) { - m_overlay_list.emplace_back(device, *itemnode, elemmap, transform); + m_overlay_list.emplace_back(env, *itemnode, elemmap, transform); } else if (!strcmp(itemnode->get_name(), "bezel")) { - m_bezel_list.emplace_back(device, *itemnode, elemmap, transform); + m_bezel_list.emplace_back(env, *itemnode, elemmap, transform); } else if (!strcmp(itemnode->get_name(), "cpanel")) { - m_cpanel_list.emplace_back(device, *itemnode, elemmap, transform); + m_cpanel_list.emplace_back(env, *itemnode, elemmap, transform); } else if (!strcmp(itemnode->get_name(), "marquee")) { - m_marquee_list.emplace_back(device, *itemnode, elemmap, transform); + m_marquee_list.emplace_back(env, *itemnode, elemmap, transform); } else if (!strcmp(itemnode->get_name(), "group")) { - char const *ref(xml_get_attribute_string_with_subst(device.machine(), *itemnode, "ref", nullptr)); + char const *ref(env.get_attribute_string(*itemnode, "ref", nullptr)); if (!ref) throw layout_syntax_error("nested group must have ref attribute"); - group_map::const_iterator const found(groupmap.find(ref)); + group_map::iterator const found(groupmap.find(ref)); if (groupmap.end() == found) throw layout_syntax_error(util::string_format("unable to find group %s", ref)); + unresolved = false; + found->second.resolve_bounds(env, groupmap); render_bounds grouptrans(transform); util::xml::data_node const *const itemboundsnode(itemnode->get_child("bounds")); if (itemboundsnode) { render_bounds itembounds; - parse_bounds(device.machine(), itemboundsnode, itembounds); + env.parse_bounds(itemboundsnode, itembounds); grouptrans = found->second.make_transform(itembounds, transform); } - add_items(device, found->second.get_groupnode(), elemmap, groupmap, grouptrans); + environment local(env); + add_items(local, found->second.get_groupnode(), elemmap, groupmap, grouptrans, false, false, true); } - else if (strcmp(itemnode->get_name(), "bounds")) + else if (!strcmp(itemnode->get_name(), "repeat")) + { + int const count(env.get_attribute_int(*itemnode, "count", -1)); + if (0 >= count) + throw layout_syntax_error("repeat must have positive integer count attribute"); + environment local(env); + for (int i = 0; count > i; ++i) + { + add_items(local, *itemnode, elemmap, groupmap, transform, false, true, !i); + local.increment_parameters(); + } + } + else { throw layout_syntax_error(util::string_format("unknown view item %s", itemnode->get_name())); } } + + if (envaltered && !unresolved) + { + for (group_map::value_type &group : groupmap) + group.second.set_bounds_unresolved(); + } } -std::string layout_view::make_name(device_t &device, util::xml::data_node const &viewnode) +std::string layout_view::make_name(environment &env, util::xml::data_node const &viewnode) { - char const *const name(xml_get_attribute_string_with_subst(device.machine(), viewnode, "name", "")); - if (&device == &device.machine().root_device()) + char const *const name(env.get_attribute_string(viewnode, "name", nullptr)); + if (!name) + throw layout_syntax_error("view must have name attribute"); + + if (env.is_root_device()) { return name; } else { - char const *tag(device.tag()); + char const *tag(env.device().tag()); if (':' == *tag) ++tag; return util::string_format("%s %s", tag, name); @@ -2648,22 +3210,21 @@ std::string layout_view::make_name(device_t &device, util::xml::data_node const //------------------------------------------------- layout_view::item::item( - device_t &device, + environment &env, util::xml::data_node const &itemnode, element_map &elemmap, render_bounds const &transform) : m_element(nullptr) - , m_output(device, xml_get_attribute_string_with_subst(device.machine(), itemnode, "name", "")) - , m_have_output(xml_get_attribute_string_with_subst(device.machine(), itemnode, "name", "")[0]) - , m_input_tag(xml_get_attribute_string_with_subst(device.machine(), itemnode, "inputtag", "")) + , m_output(env.device(), env.get_attribute_string(itemnode, "name", "")) + , m_have_output(env.get_attribute_string(itemnode, "name", "")[0]) + , m_input_tag(env.get_attribute_string(itemnode, "inputtag", "")) , m_input_port(nullptr) , m_input_mask(0) , m_screen(nullptr) , m_orientation(ROT0) { // find the associated element - running_machine &machine(device.machine()); - char const *const name = xml_get_attribute_string_with_subst(machine, itemnode, "element", nullptr); + char const *const name(env.get_attribute_string(itemnode, "element", nullptr)); if (name) { // search the list of elements for a match, error if not found @@ -2679,24 +3240,24 @@ layout_view::item::item( m_output.resolve(); // fetch common data - int index = xml_get_attribute_int_with_subst(machine, itemnode, "index", -1); + int index = env.get_attribute_int(itemnode, "index", -1); if (index != -1) - m_screen = screen_device_iterator(machine.root_device()).byindex(index); - m_input_mask = xml_get_attribute_int_with_subst(machine, itemnode, "inputmask", 0); + m_screen = screen_device_iterator(env.machine().root_device()).byindex(index); + m_input_mask = env.get_attribute_int(itemnode, "inputmask", 0); if (m_have_output && m_element) m_output = m_element->default_state(); - parse_bounds(machine, itemnode.get_child("bounds"), m_rawbounds); + env.parse_bounds(itemnode.get_child("bounds"), m_rawbounds); render_bounds_transform(m_rawbounds, transform); - parse_color(machine, itemnode.get_child("color"), m_color); - parse_orientation(machine, itemnode.get_child("orientation"), m_orientation); + env.parse_color(itemnode.get_child("color"), m_color); + env.parse_orientation(itemnode.get_child("orientation"), m_orientation); // sanity checks if (strcmp(itemnode.get_name(), "screen") == 0) { if (itemnode.has_attribute("tag")) { - char const *const tag(xml_get_attribute_string_with_subst(machine, itemnode, "tag", "")); - m_screen = dynamic_cast(device.subdevice(tag)); + char const *const tag(env.get_attribute_string(itemnode, "tag", "")); + m_screen = dynamic_cast(env.device().subdevice(tag)); if (!m_screen) throw layout_reference_error(util::string_format("invalid screen tag '%d'", tag)); } @@ -2711,7 +3272,7 @@ layout_view::item::item( } if (has_input()) - m_input_port = device.ioport(m_input_tag.c_str()); + m_input_port = env.device().ioport(m_input_tag.c_str()); } @@ -2790,7 +3351,7 @@ layout_file::layout_file(device_t &device, util::xml::data_node const &rootnode, : m_elemmap() , m_viewlist() { - running_machine &machine(device.machine()); + emu::render::detail::layout_environment env(device); try { // find the layout node @@ -2803,13 +3364,17 @@ layout_file::layout_file(device_t &device, util::xml::data_node const &rootnode, if (version != LAYOUT_VERSION) throw layout_syntax_error(util::string_format("unsupported version %d", version)); + // parse all the parameters + for (util::xml::data_node const *elemnode = mamelayoutnode->get_child("param") ; elemnode; elemnode = elemnode->get_next_sibling("param")) + env.set_parameter(*elemnode); + // parse all the elements for (util::xml::data_node const *elemnode = mamelayoutnode->get_child("element"); elemnode; elemnode = elemnode->get_next_sibling("element")) { - char const *const name(xml_get_attribute_string_with_subst(machine, *elemnode, "name", nullptr)); + char const *const name(env.get_attribute_string(*elemnode, "name", nullptr)); if (!name) throw layout_syntax_error("element lacks name attribute"); - if (!m_elemmap.emplace(std::piecewise_construct, std::forward_as_tuple(name), std::forward_as_tuple(machine, *elemnode, dirname)).second) + if (!m_elemmap.emplace(std::piecewise_construct, std::forward_as_tuple(name), std::forward_as_tuple(env, *elemnode, dirname)).second) throw layout_syntax_error(util::string_format("duplicate element name %s", name)); } @@ -2817,14 +3382,12 @@ layout_file::layout_file(device_t &device, util::xml::data_node const &rootnode, group_map groupmap; for (util::xml::data_node const *groupnode = mamelayoutnode->get_child("group"); groupnode; groupnode = groupnode->get_next_sibling("group")) { - char const *const name(xml_get_attribute_string_with_subst(machine, *groupnode, "name", nullptr)); + char const *const name(env.get_attribute_string(*groupnode, "name", nullptr)); if (!name) throw layout_syntax_error("group lacks name attribute"); - if (!groupmap.emplace(std::piecewise_construct, std::forward_as_tuple(name), std::forward_as_tuple(machine, *groupnode)).second) + if (!groupmap.emplace(std::piecewise_construct, std::forward_as_tuple(name), std::forward_as_tuple(*groupnode)).second) throw layout_syntax_error(util::string_format("duplicate group name %s", name)); } - for (group_map::value_type &group : groupmap) - group.second.resolve_bounds(groupmap); // parse all the views for (util::xml::data_node const *viewnode = mamelayoutnode->get_child("view"); viewnode != nullptr; viewnode = viewnode->get_next_sibling("view")) @@ -2835,11 +3398,11 @@ layout_file::layout_file(device_t &device, util::xml::data_node const &rootnode, // if the error is allowed to propagate, the entire layout is dropped so you can't select the useful view try { - m_viewlist.emplace_back(device, *viewnode, m_elemmap, groupmap); + m_viewlist.emplace_back(env, *viewnode, m_elemmap, groupmap); } catch (layout_reference_error const &err) { - osd_printf_warning("Error instantiating layout view %s: %s\n", xml_get_attribute_string_with_subst(machine, *viewnode, "name", ""), err.what()); + osd_printf_warning("Error instantiating layout view %s: %s\n", env.get_attribute_string(*viewnode, "name", ""), err.what()); } } } diff --git a/src/lib/util/xmlfile.cpp b/src/lib/util/xmlfile.cpp index d96c5913728..1014a7b245c 100644 --- a/src/lib/util/xmlfile.cpp +++ b/src/lib/util/xmlfile.cpp @@ -598,7 +598,7 @@ int data_node::get_attribute_int(const char *attribute, int defvalue) const stream >> std::hex >> uvalue; result = int(uvalue); } - else if (string[0] == '0' && string[1] == 'x') + else if ((string[0] == '0') && ((string[1] == 'x') || (string[1] == 'X'))) { stream.str(&string[2]); unsigned uvalue; diff --git a/src/mame/layout/intlc44.lay b/src/mame/layout/intlc44.lay index 19ea53437cf..5f64a31bd6e 100644 --- a/src/mame/layout/intlc44.lay +++ b/src/mame/layout/intlc44.lay @@ -164,21 +164,6 @@ Intel INTELLEC® 4/MOD 40 layout - - - - - - - - - - - - - - - @@ -188,16 +173,6 @@ Intel INTELLEC® 4/MOD 40 layout - - - - - - - - - - @@ -212,42 +187,10 @@ Intel INTELLEC® 4/MOD 40 layout - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -262,10 +205,6 @@ Intel INTELLEC® 4/MOD 40 layout - - - - @@ -291,42 +230,35 @@ Intel INTELLEC® 4/MOD 40 layout - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -338,31 +270,6 @@ Intel INTELLEC® 4/MOD 40 layout - - - - - - - - - - - - - - - - - - - - - - - - - @@ -386,92 +293,53 @@ Intel INTELLEC® 4/MOD 40 layout - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + @@ -487,18 +355,17 @@ Intel INTELLEC® 4/MOD 40 layout - - - - - - - - - - - - + + + + + + + + + + + diff --git a/src/mame/layout/intlc440.lay b/src/mame/layout/intlc440.lay index 1d2cb625ca2..fa2b97734e8 100644 --- a/src/mame/layout/intlc440.lay +++ b/src/mame/layout/intlc440.lay @@ -160,21 +160,6 @@ Intel INTELLEC® 4/MOD 40 layout - - - - - - - - - - - - - - - @@ -184,16 +169,6 @@ Intel INTELLEC® 4/MOD 40 layout - - - - - - - - - - @@ -208,42 +183,10 @@ Intel INTELLEC® 4/MOD 40 layout - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -258,10 +201,6 @@ Intel INTELLEC® 4/MOD 40 layout - - - - @@ -286,42 +225,35 @@ Intel INTELLEC® 4/MOD 40 layout - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -333,31 +265,6 @@ Intel INTELLEC® 4/MOD 40 layout - - - - - - - - - - - - - - - - - - - - - - - - - @@ -381,92 +288,53 @@ Intel INTELLEC® 4/MOD 40 layout - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + @@ -482,18 +350,17 @@ Intel INTELLEC® 4/MOD 40 layout - - - - - - - - - - - - + + + + + + + + + + + diff --git a/src/mame/layout/mephisto_academy.lay b/src/mame/layout/mephisto_academy.lay index 565f670185b..fbea1e63ff8 100644 --- a/src/mame/layout/mephisto_academy.lay +++ b/src/mame/layout/mephisto_academy.lay @@ -1,6 +1,6 @@ - + @@ -69,7 +69,7 @@ - + @@ -119,16 +119,15 @@ - + - - - - - - - - + + + + + + + @@ -139,7 +138,7 @@ - + @@ -184,155 +183,46 @@ - + + + + + + + + + + + + - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/src/mame/layout/ninjaw.lay b/src/mame/layout/ninjaw.lay index e0a7010ae8b..7f205058673 100644 --- a/src/mame/layout/ninjaw.lay +++ b/src/mame/layout/ninjaw.lay @@ -1,41 +1,5 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/mame/layout/playch10.lay b/src/mame/layout/playch10.lay index 088c2f0bedb..203cef8ec8a 100644 --- a/src/mame/layout/playch10.lay +++ b/src/mame/layout/playch10.lay @@ -6,30 +6,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/mame/layout/ppsatan.lay b/src/mame/layout/ppsatan.lay index 81e243edb99..8a53ac47910 100644 --- a/src/mame/layout/ppsatan.lay +++ b/src/mame/layout/ppsatan.lay @@ -1,41 +1,5 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -47,5 +11,4 @@ - diff --git a/src/mame/layout/wildfire.lay b/src/mame/layout/wildfire.lay index c2c5ef210be..7bec0a1d3d2 100644 --- a/src/mame/layout/wildfire.lay +++ b/src/mame/layout/wildfire.lay @@ -26,125 +26,18 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + +