1 // license:BSD-3-Clause
2 // copyright-holders:Phil Stroffolino
3 /****************************************************************************
4 
5     Irem M57 hardware
6 
7 ****************************************************************************/
8 
9 #include "emu.h"
10 #include "includes/m57.h"
11 
12 
13 /***************************************************************************
14 
15   Convert the color PROMs into a more useable format.
16 
17   Tropical Angel has two 256x4 character palette PROMs, one 32x8 sprite
18   palette PROM, and one 256x4 sprite color lookup table PROM.
19 
20   I don't know for sure how the palette PROMs are connected to the RGB
21   output, but it's probably something like this; note that RED and BLUE
22   are swapped wrt the usual configuration.
23 
24   bit 7 -- 220 ohm resistor  -- RED
25         -- 470 ohm resistor  -- RED
26         -- 220 ohm resistor  -- GREEN
27         -- 470 ohm resistor  -- GREEN
28         -- 1  kohm resistor  -- GREEN
29         -- 220 ohm resistor  -- BLUE
30         -- 470 ohm resistor  -- BLUE
31   bit 0 -- 1  kohm resistor  -- BLUE
32 
33 ***************************************************************************/
34 
m57_palette(palette_device & palette) const35 void m57_state::m57_palette(palette_device &palette) const
36 {
37 	const uint8_t *color_prom = memregion("proms")->base();
38 
39 	// character palette
40 	for (int i = 0; i < 256; i++)
41 	{
42 		int bit0, bit1, bit2;
43 
44 		// red component
45 		bit0 = 0;
46 		bit1 = BIT(color_prom[256], 2);
47 		bit2 = BIT(color_prom[256], 3);
48 		int const r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
49 		// green component
50 		bit0 = BIT(color_prom[0], 3);
51 		bit1 = BIT(color_prom[256], 0);
52 		bit2 = BIT(color_prom[256], 1);
53 		int const g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
54 		// blue component
55 		bit0 = BIT(color_prom[0], 0);
56 		bit1 = BIT(color_prom[0], 1);
57 		bit2 = BIT(color_prom[0], 2);
58 		int const b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
59 
60 		palette.set_indirect_color(i, rgb_t(r, g, b));
61 		palette.set_pen_indirect(i, i);
62 		color_prom++;
63 	}
64 
65 	color_prom += 256;
66 	// color_prom now points to the beginning of the sprite palette
67 
68 	// sprite palette
69 	for (int i = 0; i < 16; i++)
70 	{
71 		int bit0, bit1, bit2;
72 
73 		// red component
74 		bit0 = 0;
75 		bit1 = BIT(*color_prom, 6);
76 		bit2 = BIT(*color_prom, 7);
77 		int const r = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
78 		// green component
79 		bit0 = BIT(*color_prom, 3);
80 		bit1 = BIT(*color_prom, 4);
81 		bit2 = BIT(*color_prom, 5);
82 		int const g = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
83 		// blue component
84 		bit0 = BIT(*color_prom, 0);
85 		bit1 = BIT(*color_prom, 1);
86 		bit2 = BIT(*color_prom, 2);
87 		int const b = 0x21 * bit0 + 0x47 * bit1 + 0x97 * bit2;
88 
89 		palette.set_indirect_color(i + 256, rgb_t(r, g, b));
90 		color_prom++;
91 	}
92 
93 	color_prom += 16;
94 	// color_prom now points to the beginning of the sprite lookup table
95 
96 	// sprite lookup table
97 	for (int i = 0; i < 32 * 8; i++)
98 	{
99 		palette.set_pen_indirect(i + 32 * 8, 256 + (~*color_prom & 0x0f));
100 		color_prom++;
101 	}
102 }
103 
104 
105 /*************************************
106  *
107  *  Tilemap info callback
108  *
109  *************************************/
110 
TILE_GET_INFO_MEMBER(m57_state::get_tile_info)111 TILE_GET_INFO_MEMBER(m57_state::get_tile_info)
112 {
113 	uint8_t attr = m_videoram[tile_index * 2 + 0];
114 	uint16_t code = m_videoram[tile_index * 2 + 1] | ((attr & 0xc0) << 2);
115 
116 	tileinfo.set(0, code, attr & 0x0f, TILE_FLIPXY(attr >> 4));
117 }
118 
119 
120 /*************************************
121  *
122  *  Video RAM access
123  *
124  *************************************/
125 
m57_videoram_w(offs_t offset,uint8_t data)126 void m57_state::m57_videoram_w(offs_t offset, uint8_t data)
127 {
128 	m_videoram[offset] = data;
129 	m_bg_tilemap->mark_tile_dirty(offset / 2);
130 }
131 
132 
133 /*************************************
134  *
135  *  Video startup
136  *
137  *************************************/
138 
video_start()139 void m57_state::video_start()
140 {
141 	m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(m57_state::get_tile_info)), TILEMAP_SCAN_ROWS,  8, 8, 32, 32);
142 	m_bg_tilemap->set_scroll_rows(256);
143 
144 	save_item(NAME(m_flipscreen));
145 }
146 
147 
148 /*************************************
149  *
150  *  Outputs
151  *
152  *************************************/
153 
m57_flipscreen_w(uint8_t data)154 void m57_state::m57_flipscreen_w(uint8_t data)
155 {
156 	/* screen flip is handled both by software and hardware */
157 	m_flipscreen = (data & 0x01) ^ (~ioport("DSW2")->read() & 0x01);
158 	m_bg_tilemap->set_flip(m_flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
159 
160 	machine().bookkeeping().coin_counter_w(0,data & 0x02);
161 	machine().bookkeeping().coin_counter_w(1,data & 0x20);
162 }
163 
164 
165 /*************************************
166  *
167  *  Background rendering
168  *
169  *************************************/
170 
draw_background(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)171 void m57_state::draw_background(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
172 {
173 	// from 64 to 127: not wrapped
174 	for (int y = 64; y < 128; y++)
175 		m_bg_tilemap->set_scrollx(y, m_scrollram[0x40]);
176 
177 	m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
178 
179 	// from 128 to 255: wrapped
180 	for (int y = 128; y <= cliprect.max_y; y++)
181 	{
182 		int16_t const scrolly = m_scrollram[y] + (m_scrollram[y + 0x100] << 8);
183 
184 		if (scrolly >= 0)
185 		{
186 			for (int x = cliprect.min_x; x <= cliprect.max_x; x++)
187 			{
188 				if ((x + scrolly) <= cliprect.max_x)
189 					bitmap.pix(y, x) = bitmap.pix(y, x + scrolly);
190 				else
191 					bitmap.pix(y, x) = bitmap.pix(y, cliprect.max_x);
192 			}
193 		}
194 		else
195 		{
196 			for (int x = cliprect.max_x; x >= cliprect.min_x; x--)
197 			{
198 				if ((x + scrolly) >= cliprect.min_x)
199 					bitmap.pix(y, x) = bitmap.pix(y, x + scrolly);
200 				else
201 					bitmap.pix(y, x) = bitmap.pix(y, cliprect.min_x);
202 			}
203 		}
204 	}
205 }
206 
207 /*************************************
208  *
209  *  Sprite rendering
210  *
211  *************************************/
212 
draw_sprites(bitmap_ind16 & bitmap,const rectangle & cliprect)213 void m57_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect)
214 {
215 	int offs;
216 
217 	for (offs = m_spriteram.bytes() - 4; offs >= 0; offs -= 4)
218 	{
219 		uint8_t attributes = m_spriteram[offs + 1];
220 		int sx = m_spriteram[offs + 3];
221 		int sy = ((224 - m_spriteram[offs + 0] - 32) & 0xff) + 32;
222 		int code = m_spriteram[offs + 2];
223 		int color = attributes & 0x1f;
224 		int flipy = attributes & 0x80;
225 		int flipx = attributes & 0x40;
226 
227 		int tile_number = code & 0x3f;
228 
229 		int bank = 0;
230 		if (code & 0x80) bank += 1;
231 		if (attributes & 0x20) bank += 2;
232 
233 		if (m_flipscreen)
234 		{
235 			sx = 240 - sx;
236 			sy = 224 - sy;
237 			flipx = !flipx;
238 			flipy = !flipy;
239 		}
240 
241 		m_gfxdecode->gfx(1 + bank)->transmask(bitmap,cliprect,
242 			tile_number,
243 			color,
244 			flipx, flipy,
245 			sx, sy,
246 			m_palette->transpen_mask(*m_gfxdecode->gfx(1), color, 256 + 15));
247 	}
248 }
249 
250 
251 
252 /*************************************
253  *
254  *  Video update
255  *
256  *************************************/
257 
screen_update_m57(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)258 uint32_t m57_state::screen_update_m57(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
259 {
260 	draw_background(screen, bitmap, cliprect);
261 	draw_sprites(bitmap, cliprect);
262 	return 0;
263 }
264