summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/rendlay.h
blob: da9edfcf752d09974ae5e010f62be371e25f4e1b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
// license:BSD-3-Clause
// copyright-holders:Aaron Giles, Vas Crabb
/***************************************************************************

    rendlay.h

    Core rendering layout parser and manager.

***************************************************************************/

#ifndef MAME_EMU_RENDLAY_H
#define MAME_EMU_RENDLAY_H

#pragma once

#include "rendertypes.h"
#include "screen.h"


//**************************************************************************
//  TYPE DEFINITIONS
//**************************************************************************

namespace emu::render::detail {

struct bounds_step
{
	render_bounds get() const { return bounds; }

	int             state;
	render_bounds   bounds;
	render_bounds   delta;
};
using bounds_vector = std::vector<bounds_step>;

struct color_step
{
	render_color get() const { return color; }

	int             state;
	render_color    color;
	render_color    delta;
};
using color_vector = std::vector<color_step>;


class layout_environment;
class view_environment;

} // namespace emu::render::detail


/// \brief A description of a piece of visible artwork
///
/// Most view items (except for those referencing screens) have exactly
/// one layout_element which describes the contents of the item.
/// Elements are separate from items because they can be re-used
/// multiple times within a layout.  Even though an element can contain
/// a number of components, they are drawn as a single textured quad.
class layout_element
{
public:
	using environment = emu::render::detail::layout_environment;

	// construction/destruction
	layout_element(environment &env, util::xml::data_node const &elemnode);
	virtual ~layout_element();

	// getters
	running_machine &machine() const { return m_machine; }
	int default_state() const { return m_defstate; }
	render_texture *state_texture(int state);

	// operations
	void preload();

private:
	/// \brief A drawing component within a layout element
	///
	/// Each #layout_element contains one or more components. Each
	/// component can describe either an image or a rectangle/disk
	/// primitive.  A component can also have a state mask and value
	/// for controlling visibility.  If the state of the item
	/// instantiating the element matches the component's state value
	/// for the bits that are set in the mask, the component is visible.
	class component
	{
	public:
		typedef std::unique_ptr<component> ptr;

		// construction/destruction
		component(environment &env, util::xml::data_node const &compnode);
		virtual ~component() = default;

		// setup
		void normalize_bounds(float xoffs, float yoffs, float xscale, float yscale);

		// getters
		int statemask() const { return m_statemask; }
		int stateval() const { return m_stateval; }
		std::pair<int, bool> statewrap() const;
		render_bounds overall_bounds() const;
		render_bounds bounds(int state) const;
		render_color color(int state) const;

		// operations
		virtual void preload(running_machine &machine);
		virtual void draw(running_machine &machine, bitmap_argb32 &dest, int state);

	protected:
		// helpers
		virtual int maxstate() const;
		virtual void draw_aligned(running_machine &machine, bitmap_argb32 &dest, const rectangle &bounds, int state);

		// drawing helpers
		void draw_text(render_font &font, bitmap_argb32 &dest, const rectangle &bounds, std::string_view str, int align, const render_color &color);
		void draw_segment_horizontal_caps(bitmap_argb32 &dest, int minx, int maxx, int midy, int width, int caps, rgb_t color);
		void draw_segment_horizontal(bitmap_argb32 &dest, int minx, int maxx, int midy, int width, rgb_t color);
		void draw_segment_vertical_caps(bitmap_argb32 &dest, int miny, int maxy, int midx, int width, int caps, rgb_t color);
		void draw_segment_vertical(bitmap_argb32 &dest, int miny, int maxy, int midx, int width, rgb_t color);
		void draw_segment_diagonal_1(bitmap_argb32 &dest, int minx, int maxx, int miny, int maxy, int width, rgb_t color);
		void draw_segment_diagonal_2(bitmap_argb32 &dest, int minx, int maxx, int miny, int maxy, int width, rgb_t color);
		void draw_segment_decimal(bitmap_argb32 &dest, int midx, int midy, int width, rgb_t color);
		void draw_segment_comma(bitmap_argb32 &dest, int minx, int maxx, int miny, int maxy, int width, rgb_t color);
		void apply_skew(bitmap_argb32 &dest, int skewwidth);

	private:
		using bounds_vector = emu::render::detail::bounds_vector;
		using color_vector = emu::render::detail::color_vector;

		// internal state
		int const           m_statemask;                // bits of state used to control visibility
		int const           m_stateval;                 // masked state value to make component visible
		bounds_vector       m_bounds;                   // bounds of the element
		color_vector        m_color;                    // color of the element
	};

	// component implementations
	class image_component;
	class rect_component;
	class disk_component;
	class text_component;
	class led7seg_component;
	class led8seg_gts1_component;
	class led14seg_component;
	class led16seg_component;
	class led14segsc_component;
	class led16segsc_component;
	class simplecounter_component;
	class reel_component;

	// a texture encapsulates a texture for a given element in a given state
	class texture
	{
	public:
		texture();
		texture(texture const &that) = delete;
		texture(texture &&that);

		~texture();

		texture &operator=(texture const &that) = delete;
		texture &operator=(texture &&that);

		layout_element *    m_element;      // pointer back to the element
		render_texture *    m_texture;      // texture for this state
		int                 m_state;        // associated state number
	};

	typedef component::ptr (*make_component_func)(environment &env, util::xml::data_node const &compnode);
	typedef std::map<std::string, make_component_func> make_component_map;

	// internal helpers
	static void element_scale(bitmap_argb32 &dest, bitmap_argb32 &source, const rectangle &sbounds, void *param);
	template <typename T> static component::ptr make_component(environment &env, util::xml::data_node const &compnode);
	template <int D> static component::ptr make_dotmatrix_component(environment &env, util::xml::data_node const &compnode);

	static make_component_map const s_make_component; // maps component XML names to creator functions

	// internal state
	running_machine &           m_machine;      // reference to the owning machine
	std::vector<component::ptr> m_complist;     // list of components
	int const                   m_defstate;     // default state of this element
	int                         m_statemask;    // mask to apply to state values
	bool                        m_foldhigh;     // whether we need to fold state values above the mask range
	std::vector<texture>        m_elemtex;      // array of element textures used for managing the scaled bitmaps
};


/// \brief A reusable group of items
///
/// Views expand/flatten groups into their component elements applying
/// an optional coordinate transform.  This is useful for duplicating
/// the same sublayout in multiple views, or grouping related items to
/// simplify overall view arrangement.  Groups only exist while parsing
/// a layout file - no information about element grouping is preserved
/// after the views have been built.
class layout_group
{
public:
	using environment = emu::render::detail::layout_environment;
	using group_map = std::unordered_map<std::string, layout_group>;
	using transform = std::array<std::array<float, 3>, 3>;

	layout_group(util::xml::data_node const &groupnode);
	~layout_group();

	util::xml::data_node const &get_groupnode() const { return m_groupnode; }

	transform make_transform(int orientation, render_bounds const &dest) const;
	transform make_transform(int orientation, transform const &trans) const;
	transform make_transform(int orientation, render_bounds const &dest, transform const &trans) const;

	void set_bounds_unresolved();
	void resolve_bounds(environment &env, group_map &groupmap);

private:
	void resolve_bounds(environment &env, group_map &groupmap, std::vector<layout_group const *> &seen);
	void resolve_bounds(
			environment &env,
			util::xml::data_node const &parentnode,
			group_map &groupmap,
			std::vector<layout_group const *> &seen,
			bool &empty,
			bool vistoggle,
			bool repeat,
			bool init);

	util::xml::data_node const &    m_groupnode;
	render_bounds                   m_bounds;
	bool                            m_bounds_resolved;
};


/// \brief A single item in a view
///
/// Each view has a list of item structures describing the visual
/// elements to draw, where they are located, additional blending modes,
/// and bindings for inputs and outputs.
class layout_view_item
{
	friend class layout_view;

public:
	using view_environment = emu::render::detail::view_environment;
	using element_map = std::unordered_map<std::string, layout_element>;
	using state_delegate = delegate<int ()>;
	using bounds_delegate = delegate<render_bounds ()>;
	using color_delegate = delegate<render_color ()>;
	using scroll_size_delegate = delegate<float ()>;
	using scroll_pos_delegate = delegate<float ()>;

	// construction/destruction
	layout_view_item(
			view_environment &env,
			util::xml::data_node const &itemnode,
			element_map &elemmap,
			int orientation,
			layout_group::transform const &trans,
			render_color const &color);
	~layout_view_item();

	// getters
	std::string const &id() const { return m_id; }
	layout_element *element() const { return m_element; }
	screen_device *screen() const { return m_screen; }
	bool bounds_animated() const { return m_bounds.size() > 1U; }
	bool color_animated() const { return m_color.size() > 1U; }
	render_bounds bounds() const { return m_get_bounds(); }
	render_color color() const { return m_get_color(); }
	bool scroll_wrap_x() const { return m_scrollwrapx; }
	bool scroll_wrap_y() const { return m_scrollwrapy; }
	float scroll_size_x() const { return m_get_scroll_size_x(); }
	float scroll_size_y() const { return m_get_scroll_size_y(); }
	float scroll_pos_x() const { return m_get_scroll_pos_x(); }
	float scroll_pos_y() const { return m_get_scroll_pos_y(); }
	int blend_mode() const { return m_blend_mode; }
	u32 visibility_mask() const { return m_visibility_mask; }
	int orientation() const { return m_orientation; }
	render_container *screen_container() const { return m_screen ? &m_screen->container() : nullptr; }

	// interactivity
	bool has_input() const { return bool(m_input_port); }
	std::pair<ioport_port *, ioport_value> input_tag_and_mask() const { return std::make_pair(m_input_port, m_input_mask); };
	bool clickthrough() const { return m_clickthrough; }

	// fetch state based on configured source
	int element_state() const { return m_get_elem_state(); }
	int animation_state() const { return m_get_anim_state(); }

	// set state
	void set_state(int state) { m_elem_state = state; }
	void set_scroll_size_x(float size) { m_scrollsizex = std::clamp(size, 0.01f, 1.0f); }
	void set_scroll_size_y(float size) { m_scrollsizey = std::clamp(size, 0.01f, 1.0f); }
	void set_scroll_pos_x(float pos) { m_scrollposx = pos; }
	void set_scroll_pos_y(float pos) { m_scrollposy = pos; }

	// set handlers
	void set_element_state_callback(state_delegate &&handler);
	void set_animation_state_callback(state_delegate &&handler);
	void set_bounds_callback(bounds_delegate &&handler);
	void set_color_callback(color_delegate &&handler);
	void set_scroll_size_x_callback(scroll_size_delegate &&handler);
	void set_scroll_size_y_callback(scroll_size_delegate &&handler);
	void set_scroll_pos_x_callback(scroll_pos_delegate &&handler);
	void set_scroll_pos_y_callback(scroll_pos_delegate &&handler);

	// resolve tags, if any
	void resolve_tags();

private:
	using bounds_vector = emu::render::detail::bounds_vector;
	using color_vector = emu::render::detail::color_vector;

	state_delegate default_get_elem_state();
	state_delegate default_get_anim_state();
	bounds_delegate default_get_bounds();
	color_delegate default_get_color();
	scroll_size_delegate default_get_scroll_size_x();
	scroll_size_delegate default_get_scroll_size_y();
	scroll_pos_delegate default_get_scroll_pos_x();
	scroll_pos_delegate default_get_scroll_pos_y();
	int get_state() const;
	int get_output() const;
	int get_input_raw() const;
	int get_input_field_cached() const;
	int get_input_field_conditional() const;
	int get_anim_output() const;
	int get_anim_input() const;
	float get_scrollsizex() const;
	float get_scrollsizey() const;
	float get_scrollposx() const;
	float get_scrollposy() const;
	template <bool Wrap> float get_scrollx_output() const;
	template <bool Wrap> float get_scrolly_output() const;
	template <bool Wrap> float get_scrollx_input() const;
	template <bool Wrap> float get_scrolly_input() const;
	render_bounds get_interpolated_bounds() const;
	render_color get_interpolated_color() const;

	static layout_element *find_element(view_environment &env, util::xml::data_node const &itemnode, element_map &elemmap);
	static bounds_vector make_bounds(view_environment &env, util::xml::data_node const &itemnode, layout_group::transform const &trans);
	static color_vector make_color(view_environment &env, util::xml::data_node const &itemnode, render_color const &mult);

	// internal state
	layout_element *const   m_element;              // pointer to the associated element (non-screens only)
	state_delegate          m_get_elem_state;       // resolved element state function
	state_delegate          m_get_anim_state;       // resolved animation state function
	bounds_delegate         m_get_bounds;           // resolved bounds function
	color_delegate          m_get_color;            // resolved color function
	scroll_size_delegate    m_get_scroll_size_x;    // resolved horizontal scroll window size function
	scroll_size_delegate    m_get_scroll_size_y;    // resolved vertical scroll window size function
	scroll_pos_delegate     m_get_scroll_pos_x;     // resolved horizontal scroll position function
	scroll_pos_delegate     m_get_scroll_pos_y;     // resolved vertical scroll position function
	output_finder<>         m_output;               // associated output
	output_finder<>         m_animoutput;           // associated output for animation if different
	output_finder<>         m_scrollxoutput;        // associated output for horizontal scroll position
	output_finder<>         m_scrollyoutput;        // associated output for vertical scroll position
	ioport_port *           m_animinput_port;       // input port used for animation
	ioport_port *           m_scrollxinput_port;    // input port used for horizontal scrolling
	ioport_port *           m_scrollyinput_port;    // input port used for vertical scrolling
	bool const              m_scrollwrapx;          // whether horizontal scrolling works like a loop
	bool const              m_scrollwrapy;          // whether vertical scrolling works like a loop
	int                     m_elem_state;           // element state used in absence of bindings
	float                   m_scrollsizex;          // horizontal scroll window size used in absence of bindings
	float                   m_scrollsizey;          // vertical scroll window size used in absence of bindings
	float                   m_scrollposx;           // horizontal scroll position used in absence of bindings
	float                   m_scrollposy;           // vertical scroll position used in absence of bindings
	ioport_value const      m_animmask;             // mask for animation state
	ioport_value const      m_scrollxmask;          // mask for horizontal scroll position
	ioport_value const      m_scrollymask;          // mask for vertical scroll position
	ioport_value const      m_scrollxmin;           // minimum value for horizontal scroll position
	ioport_value const      m_scrollymin;           // minimum value for vertical scroll position
	ioport_value const      m_scrollxmax;           // maximum value for horizontal scroll position
	ioport_value const      m_scrollymax;           // maximum value for vertical scroll position
	u8 const                m_animshift;            // shift for animation state
	u8 const                m_scrollxshift;         // shift for horizontal scroll position
	u8 const                m_scrollyshift;         // shift for vertical scroll position
	ioport_port *           m_input_port;           // input port of this item
	ioport_field const *    m_input_field;          // input port field of this item
	ioport_value const      m_input_mask;           // input mask of this item
	u8 const                m_input_shift;          // input mask rightshift for raw (trailing 0s)
	bool                    m_clickthrough;         // should click pass through to lower elements
	screen_device *         m_screen;               // pointer to screen
	int const               m_orientation;          // orientation of this item
	bounds_vector           m_bounds;               // bounds of the item
	color_vector const      m_color;                // color of the item
	int                     m_blend_mode;           // blending mode to use when drawing
	u32                     m_visibility_mask;      // combined mask of parent visibility groups

	// cold items
	std::string const       m_id;                   // optional unique item identifier
	std::string const       m_input_tag;            // input tag of this item
	std::string const       m_animinput_tag;        // tag of input port for animation state
	std::string const       m_scrollxinput_tag;     // tag of input port for horizontal scroll position
	std::string const       m_scrollyinput_tag;     // tag of input port for vertical scroll position
	bounds_vector const     m_rawbounds;            // raw (original) bounds of the item
	bool const              m_have_output;          // whether we actually have an output
	bool const              m_input_raw;            // get raw data from input port
	bool const              m_have_animoutput;      // whether we actually have an output for animation
	bool const              m_have_scrollxoutput;   // whether we actually have an output for horizontal scroll
	bool const              m_have_scrollyoutput;   // whether we actually have an output for vertical scroll
	bool const              m_has_clickthrough;     // whether clickthrough was explicitly configured
};


/// \brief A single view within a #layout_file
///
/// The view is described using arbitrary coordinates that are scaled to
/// fit within the render target.  Pixels within a view are assumed to
/// be square.
class layout_view
{
public:
	using layout_environment = emu::render::detail::layout_environment;
	using view_environment = emu::render::detail::view_environment;
	using element_map = layout_view_item::element_map;
	using group_map = std::unordered_map<std::string, layout_group>;
	using screen_ref_vector = std::vector<std::reference_wrapper<screen_device const>>;
	using prepare_items_delegate = delegate<void ()>;
	using preload_delegate = delegate<void ()>;
	using recomputed_delegate = delegate<void ()>;

	using item = layout_view_item;
	using item_list = std::list<item>;
	using item_ref_vector = std::vector<std::reference_wrapper<item> >;

	/// \brief A subset of items in a view that can be hidden or shown
	///
	/// Visibility toggles allow the user to show or hide selected parts
	/// of a view.
	class visibility_toggle
	{
	public:
		// construction/destruction/assignment
		visibility_toggle(std::string &&name, u32 mask);
		visibility_toggle(visibility_toggle const &) = default;
		visibility_toggle(visibility_toggle &&) = default;
		visibility_toggle &operator=(visibility_toggle const &) = default;
		visibility_toggle &operator=(visibility_toggle &&) = default;

		// getters
		std::string const &name() const { return m_name; }
		u32 mask() const { return m_mask; }

	private:
		std::string             m_name;             // display name for the toggle
		u32                     m_mask;             // toggle combination to show
	};
	using visibility_toggle_vector = std::vector<visibility_toggle>;

	/// \brief An edge of an item in a view
	class edge
	{
	public:
		// construction/destruction
		constexpr edge(unsigned index, float position, bool trailing)
			: m_index(index)
			, m_position(position)
			, m_trailing(trailing)
		{
		}

		// getters
		constexpr unsigned index() const { return m_index; }
		constexpr float position() const { return m_position; }
		constexpr bool trailing() const { return m_trailing; }

		// comparison
		constexpr bool operator<(edge const &that) const
		{
			return std::make_tuple(m_position, m_trailing, m_index) < std::make_tuple(that.m_position, that.m_trailing, that.m_index);
		}

	private:
		unsigned                m_index;            // index of item in some collection
		float                   m_position;         // position of edge on given axis
		bool                    m_trailing;         // false for edge at lower position on axis
	};
	using edge_vector = std::vector<edge>;

	// construction/destruction
	layout_view(
			layout_environment &env,
			util::xml::data_node const &viewnode,
			element_map &elemmap,
			group_map &groupmap);
	~layout_view();

	// getters
	item *get_item(std::string const &id);
	item_list &items() { return m_items; }
	bool has_screen(screen_device const &screen) const;
	const std::string &name() const { return m_name; }
	const std::string &unqualified_name() const { return m_unqualified_name; }
	size_t visible_screen_count() const { return m_screens.size(); }
	float effective_aspect() const { return m_effaspect; }
	const render_bounds &bounds() const { return m_bounds; }
	bool has_visible_screen(screen_device const &screen) const;
	const item_ref_vector &visible_items() const { return m_visible_items; }
	const item_ref_vector &visible_screen_items() const { return m_screen_items; }
	const item_ref_vector &interactive_items() const { return m_interactive_items; }
	const edge_vector &interactive_edges_x() const { return m_interactive_edges_x; }
	const edge_vector &interactive_edges_y() const { return m_interactive_edges_y; }
	const screen_ref_vector &visible_screens() const { return m_screens; }
	const visibility_toggle_vector &visibility_toggles() const { return m_vistoggles; }
	u32 default_visibility_mask() const { return m_defvismask; }
	bool has_art() const { return m_has_art; }

	// set handlers
	void set_prepare_items_callback(prepare_items_delegate &&handler);
	void set_preload_callback(preload_delegate &&handler);
	void set_recomputed_callback(recomputed_delegate &&handler);

	// operations
	void prepare_items() { if (!m_prepare_items.isnull()) m_prepare_items(); }
	void recompute(u32 visibility_mask, bool zoom_to_screens);
	void preload();

	// resolve tags, if any
	void resolve_tags();

private:
	struct layer_lists;

	using item_id_map = std::unordered_map<
			std::reference_wrapper<std::string const>,
			item &,
			std::hash<std::string>,
			std::equal_to<std::string> >;

	// add items, recursing for groups
	void add_items(
			layer_lists &layers,
			view_environment &env,
			util::xml::data_node const &parentnode,
			element_map &elemmap,
			group_map &groupmap,
			int orientation,
			layout_group::transform const &trans,
			render_color const &color,
			bool root,
			bool repeat,
			bool init);

	static std::string make_name(layout_environment &env, util::xml::data_node const &viewnode);

	// internal state
	float                       m_effaspect;        // X/Y of the layout in current configuration
	render_bounds               m_bounds;           // computed bounds of the view in current configuration
	item_list                   m_items;            // list of layout items
	item_ref_vector             m_visible_items;    // all visible items
	item_ref_vector             m_screen_items;     // visible items that represent screens to draw
	item_ref_vector             m_interactive_items;// visible items that can accept pointer input
	edge_vector                 m_interactive_edges_x;
	edge_vector                 m_interactive_edges_y;
	screen_ref_vector           m_screens;          // list screens visible in current configuration

	// handlers
	prepare_items_delegate      m_prepare_items;    // prepare items for adding to render container
	preload_delegate            m_preload;          // additional actions when visible items change
	recomputed_delegate         m_recomputed;       // additional actions on resizing/visibility change

	// cold items
	std::string                 m_name;             // display name for the view
	std::string                 m_unqualified_name; // the name exactly as specified in the layout file
	item_id_map                 m_items_by_id;      // items with non-empty ID indexed by ID
	visibility_toggle_vector    m_vistoggles;       // collections of items that can be shown/hidden
	render_bounds               m_expbounds;        // explicit bounds of the view
	u32                         m_defvismask;       // default visibility mask
	bool                        m_has_art;          // true if the layout contains non-screen elements
};


/// \brief Layout description file
///
/// Comprises a list of elements and a list of views.  The elements are
/// reusable items that the views reference.
class layout_file
{
public:
	using element_map = std::unordered_map<std::string, layout_element>;
	using group_map = std::unordered_map<std::string, layout_group>;
	using view_list = std::list<layout_view>;
	using resolve_tags_delegate = delegate<void ()>;

	// construction/destruction
	layout_file(device_t &device, util::xml::data_node const &rootnode, char const *searchpath, char const *dirname);
	~layout_file();

	// getters
	device_t &device() const { return m_device; }
	element_map const &elements() const { return m_elemmap; }
	view_list &views() { return m_viewlist; }
	view_list const &views() const { return m_viewlist; }

	// resolve tags, if any
	void resolve_tags();

	// set handlers
	void set_resolve_tags_callback(resolve_tags_delegate &&handler);

private:
	using environment = emu::render::detail::layout_environment;

	// add elements and parameters
	void add_elements(
			environment &env,
			util::xml::data_node const &parentnode,
			group_map &groupmap,
			bool repeat,
			bool init);

	// internal state
	device_t &              m_device;       // device that caused file to be loaded
	element_map             m_elemmap;      // list of shared layout elements
	view_list               m_viewlist;     // list of views
	resolve_tags_delegate   m_resolve_tags; // additional actions after resolving tags
};

#endif // MAME_EMU_RENDLAY_H