1 // license:BSD-3-Clause
2 // copyright-holders:Takahiro Nogi. Bryan McPhail, Nicola Salmoria, Aaron Giles
3 /******************************************************************************
4 
5     Video Hardware for Video System Mahjong series and Pipe Dream.
6 
7     Driver by Takahiro Nogi <nogi@kt.rim.or.jp> 2001/02/04 -
8     and Bryan McPhail, Nicola Salmoria, Aaron Giles
9 
10 ******************************************************************************/
11 
12 #include "emu.h"
13 #include "includes/fromance.h"
14 
15 
16 
17 
18 /*************************************
19  *
20  *  Tilemap callbacks
21  *
22  *************************************/
23 
get_fromance_tile_info(tile_data & tileinfo,int tile_index,int layer)24 inline void fromance_state::get_fromance_tile_info( tile_data &tileinfo, int tile_index, int layer )
25 {
26 	int tile = ((m_local_videoram[layer][0x0000 + tile_index] & 0x80) << 9) |
27 				(m_local_videoram[layer][0x1000 + tile_index] << 8) |
28 				m_local_videoram[layer][0x2000 + tile_index];
29 	int color = m_local_videoram[layer][tile_index] & 0x7f;
30 
31 	tileinfo.set(layer, tile, color, 0);
32 }
33 
TILE_GET_INFO_MEMBER(fromance_state::get_fromance_bg_tile_info)34 TILE_GET_INFO_MEMBER(fromance_state::get_fromance_bg_tile_info){ get_fromance_tile_info(tileinfo, tile_index, 0); }
TILE_GET_INFO_MEMBER(fromance_state::get_fromance_fg_tile_info)35 TILE_GET_INFO_MEMBER(fromance_state::get_fromance_fg_tile_info){ get_fromance_tile_info(tileinfo, tile_index, 1); }
36 
37 
get_nekkyoku_tile_info(tile_data & tileinfo,int tile_index,int layer)38 inline void fromance_state::get_nekkyoku_tile_info( tile_data &tileinfo, int tile_index, int layer )
39 {
40 	int tile = (m_local_videoram[layer][0x0000 + tile_index] << 8) |
41 				m_local_videoram[layer][0x1000 + tile_index];
42 	int color = m_local_videoram[layer][tile_index + 0x2000] & 0x3f;
43 
44 	tileinfo.set(layer, tile, color, 0);
45 }
46 
TILE_GET_INFO_MEMBER(fromance_state::get_nekkyoku_bg_tile_info)47 TILE_GET_INFO_MEMBER(fromance_state::get_nekkyoku_bg_tile_info){ get_nekkyoku_tile_info(tileinfo, tile_index, 0); }
TILE_GET_INFO_MEMBER(fromance_state::get_nekkyoku_fg_tile_info)48 TILE_GET_INFO_MEMBER(fromance_state::get_nekkyoku_fg_tile_info){ get_nekkyoku_tile_info(tileinfo, tile_index, 1); }
49 
50 
51 
52 /*************************************
53  *
54  *  Video system start
55  *
56  *************************************/
57 
init_common()58 void fromance_state::init_common(  )
59 {
60 	/* allocate local videoram */
61 	m_local_videoram[0] = std::make_unique<uint8_t[]>(0x1000 * 3);
62 	m_local_videoram[1] = std::make_unique<uint8_t[]>(0x1000 * 3);
63 
64 	/* allocate local palette RAM */
65 	m_local_paletteram = std::make_unique<uint8_t[]>(0x800 * 2);
66 
67 	/* configure tilemaps */
68 	m_fg_tilemap->set_transparent_pen(15);
69 
70 	/* reset the timer */
71 	m_crtc_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(fromance_state::crtc_interrupt_gen),this));
72 
73 	/* state save */
74 	save_item(NAME(m_selected_videoram));
75 	save_pointer(NAME(m_local_videoram[0]), 0x1000 * 3);
76 	save_pointer(NAME(m_local_videoram[1]), 0x1000 * 3);
77 	save_item(NAME(m_selected_paletteram));
78 	save_item(NAME(m_scrollx));
79 	save_item(NAME(m_scrolly));
80 	save_item(NAME(m_gfxreg));
81 	save_item(NAME(m_flipscreen));
82 	save_item(NAME(m_flipscreen_old));
83 	save_item(NAME(m_scrollx_ofs));
84 	save_item(NAME(m_scrolly_ofs));
85 	save_pointer(NAME(m_local_paletteram), 0x800 * 2);
86 }
87 
VIDEO_START_MEMBER(fromance_state,fromance)88 VIDEO_START_MEMBER(fromance_state,fromance)
89 {
90 	/* allocate tilemaps */
91 	m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(fromance_state::get_fromance_bg_tile_info)), TILEMAP_SCAN_ROWS, 8, 4, 64, 64);
92 	m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(fromance_state::get_fromance_fg_tile_info)), TILEMAP_SCAN_ROWS, 8, 4, 64, 64);
93 
94 	init_common();
95 }
96 
VIDEO_START_MEMBER(fromance_state,nekkyoku)97 VIDEO_START_MEMBER(fromance_state,nekkyoku)
98 {
99 	/* allocate tilemaps */
100 	m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(fromance_state::get_nekkyoku_bg_tile_info)), TILEMAP_SCAN_ROWS, 8, 4, 64, 64);
101 	m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(fromance_state::get_nekkyoku_fg_tile_info)), TILEMAP_SCAN_ROWS, 8, 4, 64, 64);
102 
103 	init_common();
104 }
105 
VIDEO_START_MEMBER(fromance_state,pipedrm)106 VIDEO_START_MEMBER(fromance_state,pipedrm)
107 {
108 	VIDEO_START_CALL_MEMBER(fromance);
109 	m_scrolly_ofs = 0x00;
110 }
111 
VIDEO_START_MEMBER(fromance_state,hatris)112 VIDEO_START_MEMBER(fromance_state,hatris)
113 {
114 	VIDEO_START_CALL_MEMBER(fromance);
115 	m_scrollx_ofs = 0xB9;
116 	m_scrolly_ofs = 0x00;
117 }
118 
119 /*************************************
120  *
121  *  Graphics control register
122  *
123  *************************************/
124 
fromance_gfxreg_w(uint8_t data)125 void fromance_state::fromance_gfxreg_w(uint8_t data)
126 {
127 	m_gfxreg = data;
128 	m_flipscreen = (data & 0x01);
129 	m_selected_videoram = (~data >> 1) & 1;
130 	m_selected_paletteram = (data >> 6) & 1;
131 
132 	if (m_flipscreen != m_flipscreen_old)
133 	{
134 		m_flipscreen_old = m_flipscreen;
135 		machine().tilemap().set_flip_all(m_flipscreen ? (TILEMAP_FLIPX | TILEMAP_FLIPY) : 0);
136 	}
137 }
138 
139 
140 
141 /*************************************
142  *
143  *  Banked palette RAM
144  *
145  *************************************/
146 
fromance_paletteram_r(offs_t offset)147 uint8_t fromance_state::fromance_paletteram_r(offs_t offset)
148 {
149 	/* adjust for banking and read */
150 	offset |= m_selected_paletteram << 11;
151 	return m_local_paletteram[offset];
152 }
153 
154 
fromance_paletteram_w(offs_t offset,uint8_t data)155 void fromance_state::fromance_paletteram_w(offs_t offset, uint8_t data)
156 {
157 	int palword;
158 
159 	/* adjust for banking and modify */
160 	offset |= m_selected_paletteram << 11;
161 	m_local_paletteram[offset] = data;
162 
163 	/* compute R,G,B */
164 	palword = (m_local_paletteram[offset | 1] << 8) | m_local_paletteram[offset & ~1];
165 	m_palette->set_pen_color(offset / 2, pal5bit(palword >> 10), pal5bit(palword >> 5), pal5bit(palword >> 0));
166 }
167 
168 
169 
170 /*************************************
171  *
172  *  Video RAM read/write
173  *
174  *************************************/
175 
fromance_videoram_r(offs_t offset)176 uint8_t fromance_state::fromance_videoram_r(offs_t offset)
177 {
178 	return m_local_videoram[m_selected_videoram][offset];
179 }
180 
181 
fromance_videoram_w(offs_t offset,uint8_t data)182 void fromance_state::fromance_videoram_w(offs_t offset, uint8_t data)
183 {
184 	m_local_videoram[m_selected_videoram][offset] = data;
185 	(m_selected_videoram ? m_fg_tilemap : m_bg_tilemap)->mark_tile_dirty(offset & 0x0fff);
186 }
187 
188 
189 
190 /*************************************
191  *
192  *  Scroll registers
193  *
194  *************************************/
195 
fromance_scroll_w(offs_t offset,uint8_t data)196 void fromance_state::fromance_scroll_w(offs_t offset, uint8_t data)
197 {
198 	if (m_flipscreen)
199 	{
200 		switch (offset)
201 		{
202 			case 0:
203 				m_scrollx[1] = (data + (((m_gfxreg & 0x08) >> 3) * 0x100) - m_scrollx_ofs);
204 				break;
205 			case 1:
206 				m_scrolly[1] = (data + (((m_gfxreg & 0x04) >> 2) * 0x100) - m_scrolly_ofs); // - 0x10
207 				break;
208 			case 2:
209 				m_scrollx[0] = (data + (((m_gfxreg & 0x20) >> 5) * 0x100) - m_scrollx_ofs);
210 				break;
211 			case 3:
212 				m_scrolly[0] = (data + (((m_gfxreg & 0x10) >> 4) * 0x100) - m_scrolly_ofs);
213 				break;
214 		}
215 	}
216 	else
217 	{
218 
219 		switch (offset)
220 		{
221 			case 0:
222 				m_scrollx[1] = (data + (((m_gfxreg & 0x08) >> 3) * 0x100) - 0x1f7);
223 				break;
224 			case 1:
225 				m_scrolly[1] = (data + (((m_gfxreg & 0x04) >> 2) * 0x100) - 0xf9);
226 				break;
227 			case 2:
228 				m_scrollx[0] = (data + (((m_gfxreg & 0x20) >> 5) * 0x100) - 0x1f7);
229 				break;
230 			case 3:
231 				m_scrolly[0] = (data + (((m_gfxreg & 0x10) >> 4) * 0x100) - 0xf9);
232 				break;
233 		}
234 	}
235 }
236 
237 
238 
239 /*************************************
240  *
241  *  Fake video controller
242  *
243  *************************************/
244 
TIMER_CALLBACK_MEMBER(fromance_state::crtc_interrupt_gen)245 TIMER_CALLBACK_MEMBER(fromance_state::crtc_interrupt_gen)
246 {
247 	m_subcpu->set_input_line(0, HOLD_LINE);
248 	if (param != 0)
249 		m_crtc_timer->adjust(m_screen->frame_period() / param, 0, m_screen->frame_period() / param);
250 }
251 
252 /*
253  0  1  2  3  4  5
254 57 63 69 71 1f 00 (all games)
255 4f 62 69 71 1f 04 nekkyoku
256  8  9  A  B
257 7a 7b 7d 7f  (all games)
258 79 7a 7d 7f  nekkyoku (gameplay/title screen)
259 77 79 7d 7e  nekkyoku (gals display)
260  */
261 // TODO: guesswork, looks fully programmable
crtc_refresh()262 void fromance_state::crtc_refresh()
263 {
264 	if (m_gga->reg(0) == 0) // sanity check
265 		return;
266 
267 	rectangle visarea;
268 	attoseconds_t refresh;
269 
270 	visarea.min_x = 0;
271 	visarea.min_y = 0;
272 	visarea.max_x = ((m_gga->reg(0)+1)*4) - 1;
273 	visarea.max_y = 240 - 1;
274 
275 	refresh = HZ_TO_ATTOSECONDS(60);
276 
277 	m_screen->configure(512, 256, visarea, refresh);
278 }
279 
fromance_gga_data_w(offs_t offset,uint8_t data)280 void fromance_state::fromance_gga_data_w(offs_t offset, uint8_t data)
281 {
282 	switch (offset)
283 	{
284 		case 0x00:
285 			crtc_refresh();
286 			break;
287 
288 		case 0x0b:
289 			// TODO: actually is never > 0x80?
290 			m_crtc_timer->adjust(m_screen->time_until_vblank_start(), (data > 0x80) ? 2 : 1);
291 			break;
292 
293 		default:
294 			logerror("CRTC register %02X = %02X\n", offset, data);
295 			break;
296 	}
297 }
298 
299 
300 /*************************************
301  *
302  *  Main screen refresh
303  *
304  *************************************/
305 
screen_update_fromance(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)306 uint32_t fromance_state::screen_update_fromance(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
307 {
308 	m_bg_tilemap->set_scrollx(0, m_scrollx[0]);
309 	m_bg_tilemap->set_scrolly(0, m_scrolly[0]);
310 	m_fg_tilemap->set_scrollx(0, m_scrollx[1]);
311 	m_fg_tilemap->set_scrolly(0, m_scrolly[1]);
312 
313 	m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
314 	m_fg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
315 	return 0;
316 }
317 
318 
screen_update_pipedrm(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)319 uint32_t fromance_state::screen_update_pipedrm(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
320 {
321 	uint8_t* sram = m_spriteram;
322 
323 	/* there seems to be no logical mapping for the X scroll register -- maybe it's gone */
324 	m_bg_tilemap->set_scrolly(0, m_scrolly[1]);
325 	m_fg_tilemap->set_scrolly(0, m_scrolly[0]);
326 
327 	m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
328 	m_fg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
329 
330 	m_spr_old->turbofrc_draw_sprites((uint16_t*)sram, m_spriteram.bytes(), 0, bitmap, cliprect, screen.priority(), 0);
331 	m_spr_old->turbofrc_draw_sprites((uint16_t*)sram, m_spriteram.bytes(), 0, bitmap, cliprect, screen.priority(), 1);
332 	return 0;
333 }
334