text: // license:BSD-3-Clause
  // copyright-holders:Aaron Giles
  /***************************************************************************
  
      atarimo.h
  
      Common motion object management functions for Atari raster games.
  
  ***************************************************************************/
  
  #ifndef MAME_VIDEO_ATARIMO_H
  #define MAME_VIDEO_ATARIMO_H
  
  #include "video/sprite.h"
  
  
  //**************************************************************************
  //  DEVICE CONFIGURATION MACROS
  //**************************************************************************
  
  #define MCFG_ATARI_MOTION_OBJECTS_ADD(_tag, _screen, _config) \
  	MCFG_DEVICE_ADD(_tag, ATARI_MOTION_OBJECTS, 0) \
  	MCFG_VIDEO_SET_SCREEN(_screen) \
  	downcast<atari_motion_objects_device &>(*device).set_config(_config);
  
  #define MCFG_ATARI_MOTION_OBJECTS_GFXDECODE(_gfxtag) \
  	downcast<atari_motion_objects_device &>(*device).set_gfxdecode_tag("^" _gfxtag);
  
  
  //**************************************************************************
  //  TYPE DEFINITIONS
  //**************************************************************************
  
  // description of the motion objects
  struct atari_motion_objects_config
  {
  	struct entry { uint16_t data[4]; };
  	struct dual_entry { uint16_t data_lower[4]; uint16_t data_upper[4]; };
  
  	uint8_t               m_gfxindex;           // index to which gfx system
  	uint8_t               m_bankcount;          // number of motion object banks
  	bool                m_linked;             // are the entries linked?
  	bool                m_split;              // are the entries split?
  	bool                m_reverse;            // render in reverse order?
  	bool                m_swapxy;             // render in swapped X/Y order?
  	bool                m_nextneighbor;       // does the neighbor bit affect the next object?
  	uint16_t              m_slipheight;         // pixels per SLIP entry (0 for no-slip)
  	uint8_t               m_slipoffset;         // pixel offset for SLIPs
  	uint16_t              m_maxperline;         // maximum number of links to visit/scanline (0=all)
  
  	uint16_t              m_palettebase;        // base palette entry
  	uint16_t              m_maxcolors;          // maximum number of colors (remove me)
  	uint8_t               m_transpen;           // transparent pen index
  
  	entry               m_link_entry;           // mask for the link
  	dual_entry          m_code_entry;           // mask for the code index
  	dual_entry          m_color_entry;          // mask for the color/priority
  	entry               m_xpos_entry;           // mask for the X position
  	entry               m_ypos_entry;           // mask for the Y position
  	entry               m_width_entry;          // mask for the width, in tiles*/
  	entry               m_height_entry;         // mask for the height, in tiles
  	entry               m_hflip_entry;          // mask for the horizontal flip
  	entry               m_vflip_entry;          // mask for the vertical flip
  	entry               m_priority_entry;       // mask for the priority
  	entry               m_neighbor_entry;       // mask for the neighbor
  	entry               m_absolute_entry;       // mask for absolute coordinates
  	entry               m_special_entry;        // mask for the special value
  	uint16_t              m_specialvalue;         // resulting value to indicate "special"
  };
  
  
  
  // ======================> atari_motion_objects_device
  
  // device type definition
  DECLARE_DEVICE_TYPE(ATARI_MOTION_OBJECTS, atari_motion_objects_device)
  
  class atari_motion_objects_device : public sprite16_device_ind16,
  									public device_video_interface,
  									public atari_motion_objects_config
  {
  	static const int MAX_PER_BANK = 1024;
  
  public:
  	// construction/destruction
  	atari_motion_objects_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
  
  	// configuration
  	void set_gfxdecode_tag(const char *tag) { m_gfxdecode.set_tag(tag); }
  	void set_config(const atari_motion_objects_config &config) { static_cast<atari_motion_objects_config &>(*this) = config; }
  
  	// getters
  	int bank() const { return m_bank; }
  	int xscroll() const { return m_xscroll; }
  	int yscroll() const { return m_yscroll; }
  	std::vector<uint32_t> &code_lookup() { return m_codelookup; }
  	std::vector<uint8_t> &color_lookup() { return m_colorlookup; }
  	std::vector<uint8_t> &gfx_lookup() { return m_gfxlookup; }
  
  	// setters
  	void set_bank(int bank) { m_bank = bank; }
  	void set_xscroll(int xscroll) { m_xscroll = xscroll & m_bitmapxmask; }
  	void set_yscroll(int yscroll) { m_yscroll = yscroll & m_bitmapymask; }
  	void set_scroll(int xscroll, int yscroll) { set_xscroll(xscroll); set_yscroll(yscroll); }
  	void set_slipram(uint16_t *ram) { m_slipram.set_target(ram, 2); }
  
  	// rendering
  	virtual void draw(bitmap_ind16 &bitmap, const rectangle &cliprect) override;
  	void apply_stain(bitmap_ind16 &bitmap, uint16_t *pf, uint16_t *mo, int x, int y);
  
  	// memory access
  	uint16_t &slipram(int offset) { return m_slipram[offset]; }
  
  	// constants
  	static const int PRIORITY_SHIFT = 12;
  	static const uint16_t PRIORITY_MASK = (0xffff << PRIORITY_SHIFT) & 0xffff;
  	static const uint16_t DATA_MASK = PRIORITY_MASK ^ 0xffff;
  
  protected:
  	// device-level overrides
  	virtual void device_start() override;
  	virtual void device_reset() override;
  	virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
  
  private:
  	// timer IDs
  	enum
  	{
  		TID_FORCE_UPDATE
  	};
  
  	// internal helpers
  	int compute_log(int value);
  	int round_to_powerof2(int value);
  	void build_active_list(int link);
  	void render_object(bitmap_ind16 &bitmap, const rectangle &cliprect, const uint16_t *entry);
  
  	// a sprite parameter, which is a word index + shift + mask
  	class sprite_parameter
  	{
  	public:
  		sprite_parameter();
  		bool set(const atari_motion_objects_config::entry &input) { return set(input.data); }
  		bool set(const uint16_t input[4]);
  		uint16_t extract(const uint16_t *data) const { return (data[m_word] >> m_shift) & m_mask; }
  		uint16_t shift() const { return m_shift; }
  		uint16_t mask() const { return m_mask; }
  
  	private:
  		uint16_t              m_word;             // word index
  		uint16_t              m_shift;            // shift amount
  		uint16_t              m_mask;             // final mask
  	};
  
  	// a sprite parameter, which is a word index + shift + mask
  	class dual_sprite_parameter
  	{
  	public:
  		dual_sprite_parameter();
  		bool set(const atari_motion_objects_config::dual_entry &input);
  		uint32_t extract(const uint16_t *data) const { return m_lower.extract(data) | (m_upper.extract(data) << m_uppershift); }
  		uint32_t mask() const { return m_lower.mask() | (m_upper.mask() << m_uppershift); }
  
  	private:
  		sprite_parameter    m_lower;            // lower parameter
  		sprite_parameter    m_upper;            // upper parameter
  		uint16_t              m_uppershift;       // upper shift
  	};
  
  	// parameter masks
  	sprite_parameter        m_linkmask;         // mask for the link
  	sprite_parameter        m_gfxmask;          // mask for the graphics bank
  	dual_sprite_parameter   m_codemask;         // mask for the code index
  	dual_sprite_parameter   m_colormask;        // mask for the color
  	sprite_parameter        m_xposmask;         // mask for the X position
  	sprite_parameter        m_yposmask;         // mask for the Y position
  	sprite_parameter        m_widthmask;        // mask for the width, in tiles*/
  	sprite_parameter        m_heightmask;       // mask for the height, in tiles
  	sprite_parameter        m_hflipmask;        // mask for the horizontal flip
  	sprite_parameter        m_vflipmask;        // mask for the vertical flip
  	sprite_parameter        m_prioritymask;     // mask for the priority
  	sprite_parameter        m_neighbormask;     // mask for the neighbor
  	sprite_parameter        m_absolutemask;     // mask for absolute coordinates
  	sprite_parameter        m_specialmask;      // mask for the special value
  
  	// derived tile information
  	int                     m_tilewidth;          // width of non-rotated tile
  	int                     m_tileheight;         // height of non-rotated tile
  	int                     m_tilexshift;         // bits to shift X coordinate when drawing
  	int                     m_tileyshift;         // bits to shift Y coordinate when drawing
  
  	// derived bitmap information
  	int                     m_bitmapwidth;        // width of the full playfield bitmap
  	int                     m_bitmapheight;       // height of the full playfield bitmap
  	int                     m_bitmapxmask;        // x coordinate mask for the playfield bitmap
  	int                     m_bitmapymask;        // y coordinate mask for the playfield bitmap
  
  	// derived sprite information
  	int                     m_entrycount;         // number of entries per bank
  	int                     m_entrybits;          // number of bits needed to represent entrycount
  	int                     m_spriterammask;      // combined mask when accessing sprite RAM with raw addresses
  	int                     m_spriteramsize;      // total size of sprite RAM, in entries
  	int                     m_slipshift;          // log2(pixels_per_SLIP)
  	int                     m_sliprammask;        // combined mask when accessing SLIP RAM with raw addresses
  	int                     m_slipramsize;        // total size of SLIP RAM, in entries
  
  	// live state
  	emu_timer *             m_force_update_timer;   // timer for forced updating
  	uint32_t                  m_bank;               // current bank number
  	uint32_t                  m_xscroll;            // xscroll offset
  	uint32_t                  m_yscroll;            // yscroll offset
  
  	// arrays
  	optional_shared_ptr<uint16_t> m_slipram;    // pointer to the SLIP RAM
  	std::vector<uint32_t>   m_codelookup;       // lookup table for codes
  	std::vector<uint8_t>    m_colorlookup;       // lookup table for colors
  	std::vector<uint8_t>    m_gfxlookup;         // lookup table for graphics
  
  	uint16_t                  m_activelist[MAX_PER_BANK*4]; // active list
  	uint16_t *                m_activelast;           // last entry in the active list
  
  	uint32_t                  m_last_xpos;          // (during processing) the previous X position
  	uint32_t                  m_next_xpos;          // (during processing) the next X position
  	required_device<gfxdecode_device> m_gfxdecode;
  };
  
  
  #endif // MAME_VIDEO_ATARIMO_H
  