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