1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles
3 /***************************************************************************
4 
5     Atari Gauntlet hardware
6 
7 ****************************************************************************/
8 
9 #include "emu.h"
10 #include "includes/gauntlet.h"
11 
12 
13 
14 /*************************************
15  *
16  *  Tilemap callbacks
17  *
18  *************************************/
19 
TILE_GET_INFO_MEMBER(gauntlet_state::get_alpha_tile_info)20 TILE_GET_INFO_MEMBER(gauntlet_state::get_alpha_tile_info)
21 {
22 	uint16_t data = m_alpha_tilemap->basemem_read(tile_index);
23 	int code = data & 0x3ff;
24 	int color = ((data >> 10) & 0x0f) | ((data >> 9) & 0x20);
25 	int opaque = data & 0x8000;
26 	tileinfo.set(1, code, color, opaque ? TILE_FORCE_LAYER0 : 0);
27 }
28 
29 
TILE_GET_INFO_MEMBER(gauntlet_state::get_playfield_tile_info)30 TILE_GET_INFO_MEMBER(gauntlet_state::get_playfield_tile_info)
31 {
32 	uint16_t data = m_playfield_tilemap->basemem_read(tile_index);
33 	int code = ((m_playfield_tile_bank * 0x1000) + (data & 0xfff)) ^ 0x800;
34 	int color = 0x10 + (m_playfield_color_bank * 8) + ((data >> 12) & 7);
35 	tileinfo.set(0, code, color, (data >> 15) & 1);
36 }
37 
38 
39 
40 /*************************************
41  *
42  *  Video system start
43  *
44  *************************************/
45 
46 const atari_motion_objects_config gauntlet_state::s_mob_config =
47 {
48 	0,                  /* index to which gfx system */
49 	1,                  /* number of motion object banks */
50 	1,                  /* are the entries linked? */
51 	1,                  /* are the entries split? */
52 	0,                  /* render in reverse order? */
53 	0,                  /* render in swapped X/Y order? */
54 	0,                  /* does the neighbor bit affect the next object? */
55 	8,                  /* pixels per SLIP entry (0 for no-slip) */
56 	1,                  /* pixel offset for SLIPs */
57 	0,                  /* maximum number of links to visit/scanline (0=all) */
58 
59 	0x100,              /* base palette entry */
60 	0x100,              /* maximum number of colors */
61 	0,                  /* transparent pen index */
62 
63 	{{ 0,0,0,0x03ff }}, /* mask for the link */
64 	{{ 0x7fff,0,0,0 }}, /* mask for the code index */
65 	{{ 0,0x000f,0,0 }}, /* mask for the color */
66 	{{ 0,0xff80,0,0 }}, /* mask for the X position */
67 	{{ 0,0,0xff80,0 }}, /* mask for the Y position */
68 	{{ 0,0,0x0038,0 }}, /* mask for the width, in tiles*/
69 	{{ 0,0,0x0007,0 }}, /* mask for the height, in tiles */
70 	{{ 0,0,0x0040,0 }}, /* mask for the horizontal flip */
71 	{{ 0 }},            /* mask for the vertical flip */
72 	{{ 0 }},            /* mask for the priority */
73 	{{ 0 }},            /* mask for the neighbor */
74 	{{ 0 }},            /* mask for absolute coordinates */
75 
76 	{{ 0 }},            /* mask for the special value */
77 	0                   /* resulting value to indicate "special" */
78 };
79 
video_start()80 void gauntlet_state::video_start()
81 {
82 	/* modify the motion object code lookup table to account for the code XOR */
83 	std::vector<uint32_t> &codelookup = m_mob->code_lookup();
84 	for (auto & elem : codelookup)
85 		elem ^= 0x800;
86 
87 	/* set up the base color for the playfield */
88 	m_playfield_color_bank = m_vindctr2_screen_refresh ? 0 : 1;
89 
90 	/* save states */
91 	save_item(NAME(m_playfield_tile_bank));
92 	save_item(NAME(m_playfield_color_bank));
93 }
94 
95 
96 
97 /*************************************
98  *
99  *  Horizontal scroll register
100  *
101  *************************************/
102 
gauntlet_xscroll_w(offs_t offset,uint16_t data,uint16_t mem_mask)103 void gauntlet_state::gauntlet_xscroll_w(offs_t offset, uint16_t data, uint16_t mem_mask)
104 {
105 	uint16_t oldxscroll = *m_xscroll;
106 	COMBINE_DATA(m_xscroll);
107 
108 	/* if something changed, force a partial update */
109 	if (*m_xscroll != oldxscroll)
110 	{
111 		m_screen->update_partial(m_screen->vpos());
112 
113 		/* adjust the scrolls */
114 		m_playfield_tilemap->set_scrollx(0, *m_xscroll);
115 		m_mob->set_xscroll(*m_xscroll & 0x1ff);
116 	}
117 }
118 
119 
120 
121 /*************************************
122  *
123  *  Vertical scroll/PF bank register
124  *
125  *************************************/
126 
gauntlet_yscroll_w(offs_t offset,uint16_t data,uint16_t mem_mask)127 void gauntlet_state::gauntlet_yscroll_w(offs_t offset, uint16_t data, uint16_t mem_mask)
128 {
129 	uint16_t oldyscroll = *m_yscroll;
130 	COMBINE_DATA(m_yscroll);
131 
132 	/* if something changed, force a partial update */
133 	if (*m_yscroll != oldyscroll)
134 	{
135 		m_screen->update_partial(m_screen->vpos());
136 
137 		/* if the bank changed, mark all tiles dirty */
138 		if (m_playfield_tile_bank != (*m_yscroll & 3))
139 		{
140 			m_playfield_tile_bank = *m_yscroll & 3;
141 			m_playfield_tilemap->mark_all_dirty();
142 		}
143 
144 		/* adjust the scrolls */
145 		m_playfield_tilemap->set_scrolly(0, *m_yscroll >> 7);
146 		m_mob->set_yscroll((*m_yscroll >> 7) & 0x1ff);
147 	}
148 }
149 
150 
151 
152 /*************************************
153  *
154  *  Main refresh
155  *
156  *************************************/
157 
screen_update_gauntlet(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)158 uint32_t gauntlet_state::screen_update_gauntlet(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
159 {
160 	// start drawing
161 	m_mob->draw_async(cliprect);
162 
163 	/* draw the playfield */
164 	m_playfield_tilemap->draw(screen, bitmap, cliprect, 0, 0);
165 
166 	/* draw and merge the MO */
167 	bitmap_ind16 &mobitmap = m_mob->bitmap();
168 	for (const sparse_dirty_rect *rect = m_mob->first_dirty_rect(cliprect); rect != nullptr; rect = rect->next())
169 		for (int y = rect->top(); y <= rect->bottom(); y++)
170 		{
171 			uint16_t const *const mo = &mobitmap.pix(y);
172 			uint16_t *const pf = &bitmap.pix(y);
173 			for (int x = rect->left(); x <= rect->right(); x++)
174 				if (mo[x] != 0xffff)
175 				{
176 					/* verified via schematics:
177 
178 					    MO pen 1 clears PF color bit 0x80
179 					*/
180 					if ((mo[x] & 0x0f) == 1)
181 					{
182 						/* Vindicators Part II has extra logic here for the bases */
183 						if (!m_vindctr2_screen_refresh || (mo[x] & 0xf0) != 0)
184 							pf[x] ^= 0x80;
185 					}
186 					else
187 						pf[x] = mo[x];
188 				}
189 		}
190 
191 	/* add the alpha on top */
192 	m_alpha_tilemap->draw(screen, bitmap, cliprect, 0, 0);
193 	return 0;
194 }
195