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