1 // license:BSD-3-Clause
2 // copyright-holders:Nicola Salmoria
3 /***************************************************************************
4 
5     Technos Mysterious Stones hardware
6 
7     driver by Nicola Salmoria
8 
9     There are only a few differences between the video hardware of Mysterious
10     Stones and Mat Mania. The tile bank select bit is different and the sprite
11     selection seems to be different as well. Additionally, the palette is stored
12     differently. I'm also not sure that the 2nd tile page is really used in
13     Mysterious Stones.
14 
15 ***************************************************************************/
16 
17 #include "emu.h"
18 #include "video/resnet.h"
19 #include "includes/mystston.h"
20 
21 
22 
23 /*************************************
24  *
25  *  Video timing constants
26  *
27  *************************************/
28 // HMC20
29 // set_raw(XTAL(12'000'000)/2, 384, 0, 256, 272, 8, 248)
30 #define PIXEL_CLOCK     (XTAL(12'000'000) / 2)
31 #define HTOTAL          (384)
32 #define HBEND           (0)
33 #define HBSTART         (256)
34 #define VTOTAL          (272)  /* counts from 0x08-0xff, then from 0xe8-0xff */
35 #define VBEND           (8)
36 #define VBSTART         (248)
37 #define FIRST_INT_VPOS  (0x008)
38 #define INT_HPOS        (0x100)
39 
40 
41 
42 /*************************************
43  *
44  *  Scanline interrupt system
45  *
46  *  There is an interrupt every 16
47  *  scanlines, starting with 8.
48  *
49  *************************************/
50 
TIMER_CALLBACK_MEMBER(mystston_state::interrupt_callback)51 TIMER_CALLBACK_MEMBER(mystston_state::interrupt_callback)
52 {
53 	int scanline = param;
54 
55 	mystston_on_scanline_interrupt();
56 
57 	scanline = scanline + 16;
58 	if (scanline >= VTOTAL)
59 		scanline = FIRST_INT_VPOS;
60 
61 	/* the vertical synch chain is clocked by H256 -- this is probably not important, but oh well */
62 	m_interrupt_timer->adjust(m_screen->time_until_pos(scanline - 1, INT_HPOS), scanline);
63 }
64 
65 
66 
67 /*************************************
68  *
69  *  Palette handling
70  *
71  *************************************/
72 
set_palette()73 void mystston_state::set_palette()
74 {
75 	int i;
76 	static const int resistances_rg[3] = { 4700, 3300, 1500 };
77 	static const int resistances_b [2] = { 3300, 1500 };
78 	double weights_rg[3], weights_b[2];
79 
80 	uint8_t *color_prom = memregion("proms")->base();
81 
82 	compute_resistor_weights(0, 255, -1.0,
83 			3, resistances_rg, weights_rg, 0, 4700,
84 			2, resistances_b,  weights_b,  0, 4700,
85 			0, nullptr, nullptr, 0, 0);
86 
87 	for (i = 0; i < 0x40; i++)
88 	{
89 		uint8_t data;
90 		int r, g, b;
91 		int bit0, bit1, bit2;
92 
93 		/* first half is dynamic, second half is from the PROM */
94 		if (i & 0x20)
95 			data = color_prom[i & 0x1f];
96 		else
97 			data = m_paletteram[i];
98 
99 		/* red component */
100 		bit0 = (data >> 0) & 0x01;
101 		bit1 = (data >> 1) & 0x01;
102 		bit2 = (data >> 2) & 0x01;
103 		r = combine_weights(weights_rg, bit0, bit1, bit2);
104 
105 		/* green component */
106 		bit0 = (data >> 3) & 0x01;
107 		bit1 = (data >> 4) & 0x01;
108 		bit2 = (data >> 5) & 0x01;
109 		g = combine_weights(weights_rg, bit0, bit1, bit2);
110 
111 		/* blue component */
112 		bit0 = (data >> 6) & 0x01;
113 		bit1 = (data >> 7) & 0x01;
114 		b = combine_weights(weights_b, bit0, bit1);
115 
116 		m_palette->set_pen_color(i, rgb_t(r, g, b));
117 	}
118 }
119 
120 
121 
122 /*************************************
123  *
124  *  Video control register
125  *
126  *************************************/
127 
mystston_video_control_w(uint8_t data)128 void mystston_state::mystston_video_control_w(uint8_t data)
129 {
130 	*m_video_control = data;
131 
132 	/* D0-D1 - foreground text color */
133 	/* D2 - background page select */
134 	/* D3 - unused */
135 
136 	/* D4-D5 - coin counters in flipped order */
137 	machine().bookkeeping().coin_counter_w(0, data & 0x20);
138 	machine().bookkeeping().coin_counter_w(1, data & 0x10);
139 
140 	/* D6 - unused */
141 	/* D7 - screen flip */
142 }
143 
144 
145 
146 /*************************************
147  *
148  *  Tilemap callbacks
149  *
150  *************************************/
151 
TILE_GET_INFO_MEMBER(mystston_state::get_bg_tile_info)152 TILE_GET_INFO_MEMBER(mystston_state::get_bg_tile_info)
153 {
154 	int page = (*m_video_control & 0x04) << 8;
155 	int code = ((m_bg_videoram[page | 0x200 | tile_index] & 0x01) << 8) | m_bg_videoram[page | tile_index];
156 	int flags = (tile_index & 0x10) ? TILE_FLIPY : 0;
157 
158 	tileinfo.set(1, code, 0, flags);
159 }
160 
161 
TILE_GET_INFO_MEMBER(mystston_state::get_fg_tile_info)162 TILE_GET_INFO_MEMBER(mystston_state::get_fg_tile_info)
163 {
164 	int code = ((m_fg_videoram[0x400 | tile_index] & 0x07) << 8) | m_fg_videoram[tile_index];
165 	int color = ((*m_video_control & 0x01) << 1) | ((*m_video_control & 0x02) >> 1);
166 
167 	tileinfo.set(0, code, color, 0);
168 }
169 
170 
171 
172 /*************************************
173  *
174  *  Sprite drawing
175  *
176  *************************************/
177 
draw_sprites(bitmap_ind16 & bitmap,const rectangle & cliprect,gfx_element * gfx,int flip)178 void mystston_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect, gfx_element *gfx, int flip)
179 {
180 	int offs;
181 
182 	for (offs = 0; offs < 0x60; offs += 4)
183 	{
184 		int attr = m_spriteram[offs];
185 
186 		if (attr & 0x01)
187 		{
188 			int code = ((attr & 0x10) << 4) | m_spriteram[offs + 1];
189 			int color = (attr & 0x08) >> 3;
190 			int flipx = attr & 0x04;
191 			int flipy = attr & 0x02;
192 			int x = 240 - m_spriteram[offs + 3];
193 			int y = (240 - m_spriteram[offs + 2]) & 0xff;
194 
195 			if (flip)
196 			{
197 				x = 240 - x;
198 				y = 240 - y;
199 				flipx = !flipx;
200 				flipy = !flipy;
201 			}
202 
203 				gfx->transpen(bitmap,cliprect, code, color, flipx, flipy, x, y, 0);
204 		}
205 	}
206 }
207 
208 
209 
210 /*************************************
211  *
212  *  Start
213  *
214  *************************************/
215 
video_start()216 void mystston_state::video_start()
217 {
218 	m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(mystston_state::get_bg_tile_info)), TILEMAP_SCAN_COLS_FLIP_X, 16, 16, 16, 32);
219 
220 	m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(mystston_state::get_fg_tile_info)), TILEMAP_SCAN_COLS_FLIP_X,  8,  8, 32, 32);
221 	m_fg_tilemap->set_transparent_pen(0);
222 
223 	/* create the interrupt timer */
224 	m_interrupt_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mystston_state::interrupt_callback),this));
225 }
226 
227 
228 
229 /*************************************
230  *
231  *  Reset
232  *
233  *************************************/
234 
video_reset()235 void mystston_state::video_reset()
236 {
237 	m_interrupt_timer->adjust(m_screen->time_until_pos(FIRST_INT_VPOS - 1, INT_HPOS), FIRST_INT_VPOS);
238 }
239 
240 
241 
242 /*************************************
243  *
244  *  Update
245  *
246  *************************************/
247 
screen_update_mystston(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)248 uint32_t mystston_state::screen_update_mystston(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
249 {
250 	int flip = (*m_video_control & 0x80) ^ ((ioport("DSW1")->read() & 0x20) << 2);
251 
252 	set_palette();
253 
254 	machine().tilemap().mark_all_dirty();
255 	m_bg_tilemap->set_scrolly(0, *m_scroll);
256 	machine().tilemap().set_flip_all(flip ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0);
257 
258 	m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
259 	draw_sprites(bitmap, cliprect, m_gfxdecode->gfx(2), flip);
260 	m_fg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
261 
262 	return 0;
263 }
264 
265 
266 
267 /*************************************
268  *
269  *  Graphics decoding
270  *
271  *************************************/
272 
273 static const gfx_layout charlayout =
274 {
275 	8,8,
276 	RGN_FRAC(1,3),
277 	3,
278 	{ RGN_FRAC(2,3), RGN_FRAC(1,3), RGN_FRAC(0,3) },
279 	{ 0, 1, 2, 3, 4, 5, 6, 7 },
280 	{ 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 },
281 	8*8
282 };
283 
284 
285 static const gfx_layout spritelayout =
286 {
287 	16,16,
288 	RGN_FRAC(1,3),
289 	3,
290 	{ RGN_FRAC(2,3), RGN_FRAC(1,3), RGN_FRAC(0,3) },
291 	{ 16*8+0, 16*8+1, 16*8+2, 16*8+3, 16*8+4, 16*8+5, 16*8+6, 16*8+7,
292 		16*0+0, 16*0+1, 16*0+2, 16*0+3, 16*0+4, 16*0+5, 16*0+6, 16*0+7 },
293 	{ 0*8, 1*8,  2*8,  3*8,  4*8,  5*8,  6*8,  7*8,
294 		8*8, 9*8, 10*8, 11*8, 12*8, 13*8, 14*8, 15*8 },
295 	32*8
296 };
297 
298 
299 static GFXDECODE_START( gfx_mystston )
300 	GFXDECODE_ENTRY( "gfx1", 0, charlayout,   4*8, 4 )
301 	GFXDECODE_ENTRY( "gfx2", 0, spritelayout, 2*8, 1 )
302 	GFXDECODE_ENTRY( "gfx1", 0, spritelayout, 0*8, 2 )
303 GFXDECODE_END
304 
305 
306 
307 /*************************************
308  *
309  *  Machine driver
310  *
311  *************************************/
312 
mystston_video(machine_config & config)313 void mystston_state::mystston_video(machine_config &config)
314 {
315 	GFXDECODE(config, m_gfxdecode, m_palette, gfx_mystston);
316 	PALETTE(config, m_palette).set_entries(0x40);
317 
318 	SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
319 	m_screen->set_raw(PIXEL_CLOCK, HTOTAL, HBEND, HBSTART, VTOTAL, VBEND, VBSTART);
320 	m_screen->set_screen_update(FUNC(mystston_state::screen_update_mystston));
321 	m_screen->set_palette("palette");
322 }
323