1 // license:BSD-3-Clause
2 // copyright-holders:Luca Elia, Olivier Galibert
3 /***************************************************************************
4 
5   video.c
6 
7   Functions to emulate the video hardware of the machine.
8 
9 d800-dbff   foreground:         char low bits (1 screen * 1024 chars/screen)
10 dc00-dfff   foreground attribute:   7       ?
11                          6543       color
12                              21 ?
13                                0    char hi bit
14 
15 
16 e000-e0ff   spriteram:  64 sprites (4 bytes/sprite)
17         offset :    0       1       2       3
18         meaning:    ypos(lo)    sprite(lo)  attribute   xpos(lo)
19                                 7   flipy
20                                 6   flipx
21                                 5-2 color
22                                 1   sprite(hi)
23                                 0   xpos(hi)
24 
25 
26 background: 0x4000 bytes of ROM:    76543210    tile code low bits
27         0x4000 bytes of ROM:    7       ?
28                          6543       color
29                              2  ?
30                               10    tile code high bits
31 
32 ***************************************************************************/
33 
34 #include "emu.h"
35 #include "includes/galivan.h"
36 
37 /* Layers has only bits 5-7 active.
38    7 selects text off/on
39    6 selects background off/on
40    5 controls sprite priority (active only on title screen,
41      not for scores or push start nor game)
42 */
43 
44 
45 /* Notes:
46      layers are used in galivan/dangar but not ninjemak
47      ninjemak_dispdisable is used in ninjemak but not galivan/dangar
48 */
49 
50 
51 
52 /***************************************************************************
53 
54   Convert the color PROMs into a more useable format.
55 
56 ***************************************************************************/
57 
galivan_palette(palette_device & palette) const58 void galivan_state::galivan_palette(palette_device &palette) const
59 {
60 	const uint8_t *color_prom = memregion("proms")->base();
61 
62 	// create a lookup table for the palette
63 	for (int i = 0; i < 0x100; i++)
64 	{
65 		int const r = pal4bit(color_prom[i + 0x000]);
66 		int const g = pal4bit(color_prom[i + 0x100]);
67 		int const b = pal4bit(color_prom[i + 0x200]);
68 
69 		palette.set_indirect_color(i, rgb_t(r, g, b));
70 	}
71 
72 	// color_prom now points to the beginning of the lookup table
73 	color_prom += 0x300;
74 
75 	// characters use colors 0-0x3f
76 	// the bottom two bits of the color code select the palette bank for pens 0-7;
77 	// the top two bits for pens 8-15.
78 	for (int i = 0; i < 0x100; i++)
79 	{
80 		uint8_t const ctabentry = (i & 0x0f) | ((i >> ((i & 0x08) ? 2 : 0)) & 0x30);
81 
82 		palette.set_pen_indirect(i, ctabentry);
83 	}
84 
85 	// I think that background tiles use colors 0xc0-0xff in four banks
86 	// the bottom two bits of the color code select the palette bank for pens 0-7;
87 	// the top two bits for pens 8-15.
88 	for (int i = 0; i < 0x100; i++)
89 	{
90 		uint8_t const ctabentry = 0xc0 | (i & 0x0f) | ((i >> ((i & 0x08) ? 2 : 0)) & 0x30);
91 
92 		palette.set_pen_indirect(0x100 + i, ctabentry);
93 	}
94 
95 	// sprites use colors 0x80-0xbf in four banks
96 	// The lookup table tells which colors to pick from the selected bank
97 	// the bank is selected by another PROM and depends on the top 7 bits of the sprite code.
98 	// The PROM selects the bank *separately* for pens 0-7 and 8-15 (like for tiles).
99 	for (int i = 0; i < 0x1000; i++)
100 	{
101 		uint8_t const ctabentry = 0x80 | ((i << ((i & 0x80) ? 2 : 4)) & 0x30) | (color_prom[i >> 4] & 0x0f);
102 		int const i_swapped = ((i & 0x0f) << 8) | ((i & 0xff0) >> 4);
103 
104 		palette.set_pen_indirect(0x200 + i_swapped, ctabentry);
105 	}
106 }
107 
ninjemak_palette(palette_device & palette) const108 void galivan_state::ninjemak_palette(palette_device& palette) const
109 {
110 	const uint8_t *color_prom = memregion("proms")->base();
111 
112 	// create a lookup table for the palette
113 	for (int i = 0; i < 0x100; i++)
114 	{
115 		int const r = pal4bit(color_prom[i + 0x000]);
116 		int const g = pal4bit(color_prom[i + 0x100]);
117 		int const b = pal4bit(color_prom[i + 0x200]);
118 
119 		palette.set_indirect_color(i, rgb_t(r, g, b));
120 	}
121 
122 	// color_prom now points to the beginning of the lookup table
123 	color_prom += 0x300;
124 
125 	// characters use colors 0-0x7f
126 	for (int i = 0; i < 0x80; i++)
127 		palette.set_pen_indirect(i, i);
128 
129 	// I think that background tiles use colors 0xc0-0xff in four banks
130 	// the bottom two bits of the color code select the palette bank for pens 0-7;
131 	// the top two bits for pens 8-15.
132 	for (int i = 0; i < 0x100; i++)
133 	{
134 		uint8_t const ctabentry = 0xc0 | (i & 0x0f) | ((i >> ((i & 0x08) ? 2 : 0)) & 0x30);
135 
136 		palette.set_pen_indirect(0x80 + i, ctabentry);
137 	}
138 
139 	// sprites use colors 0x80-0xbf in four banks
140 	// The lookup table tells which colors to pick from the selected bank
141 	// the bank is selected by another PROM and depends on the top 7 bits of the sprite code.
142 	// The PROM selects the bank *separately* for pens 0-7 and 8-15 (like for tiles).
143 	for (int i = 0; i < 0x1000; i++)
144 	{
145 		uint8_t const ctabentry = 0x80 | ((i << ((i & 0x80) ? 2 : 4)) & 0x30) | (color_prom[i >> 4] & 0x0f);
146 		int const i_swapped = ((i & 0x0f) << 8) | ((i & 0xff0) >> 4);
147 
148 		palette.set_pen_indirect(0x180 + i_swapped, ctabentry);
149 	}
150 }
151 
152 
153 
154 /***************************************************************************
155 
156   Callbacks for the TileMap code
157 
158 ***************************************************************************/
159 
TILE_GET_INFO_MEMBER(galivan_state::get_bg_tile_info)160 TILE_GET_INFO_MEMBER(galivan_state::get_bg_tile_info)
161 {
162 	uint8_t *BGROM = memregion("gfx4")->base();
163 	int attr = BGROM[tile_index + 0x4000];
164 	int code = BGROM[tile_index] | ((attr & 0x03) << 8);
165 	tileinfo.set(1,
166 			code,
167 			(attr & 0x78) >> 3,     /* seems correct */
168 			0);
169 }
170 
TILE_GET_INFO_MEMBER(galivan_state::get_tx_tile_info)171 TILE_GET_INFO_MEMBER(galivan_state::get_tx_tile_info)
172 {
173 	int attr = m_videoram[tile_index + 0x400];
174 	int code = m_videoram[tile_index] | ((attr & 0x01) << 8);
175 	tileinfo.set(0,
176 			code,
177 			(attr & 0x78) >> 3,     /* seems correct */
178 			0);
179 	tileinfo.category = attr & 8 ? 0 : 1;   /* seems correct */
180 }
181 
TILE_GET_INFO_MEMBER(galivan_state::ninjemak_get_bg_tile_info)182 TILE_GET_INFO_MEMBER(galivan_state::ninjemak_get_bg_tile_info)
183 {
184 	uint8_t *BGROM = memregion("gfx4")->base();
185 	int attr = BGROM[tile_index + 0x4000];
186 	int code = BGROM[tile_index] | ((attr & 0x03) << 8);
187 	tileinfo.set(1,
188 			code,
189 			((attr & 0x60) >> 3) | ((attr & 0x0c) >> 2),    /* seems correct */
190 			0);
191 }
192 
TILE_GET_INFO_MEMBER(galivan_state::ninjemak_get_tx_tile_info)193 TILE_GET_INFO_MEMBER(galivan_state::ninjemak_get_tx_tile_info)
194 {
195 	uint16_t index = tile_index;
196 	// TODO: skip drawing the NB1414M4 params, how the HW actually handles this?
197 	if (index < 0x12)
198 		index = 0x12;
199 
200 	int attr = m_videoram[index + 0x400];
201 	int code = m_videoram[index] | ((attr & 0x03) << 8);
202 	tileinfo.set(0,
203 			code,
204 			(attr & 0x1c) >> 2,     /* seems correct ? */
205 			0);
206 }
207 
208 
209 
210 /***************************************************************************
211 
212   Start the video hardware emulation.
213 
214 ***************************************************************************/
215 
VIDEO_START_MEMBER(galivan_state,galivan)216 VIDEO_START_MEMBER(galivan_state,galivan)
217 {
218 	m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(galivan_state::get_bg_tile_info)), TILEMAP_SCAN_ROWS, 16, 16, 128, 128);
219 	m_tx_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(galivan_state::get_tx_tile_info)), TILEMAP_SCAN_COLS, 8, 8, 32, 32);
220 
221 	m_tx_tilemap->set_transparent_pen(15);
222 }
223 
VIDEO_START_MEMBER(galivan_state,ninjemak)224 VIDEO_START_MEMBER(galivan_state,ninjemak)
225 {
226 	m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(galivan_state::ninjemak_get_bg_tile_info)), TILEMAP_SCAN_COLS, 16, 16, 512, 32);
227 	m_tx_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(galivan_state::ninjemak_get_tx_tile_info)), TILEMAP_SCAN_COLS, 8, 8, 32, 32);
228 
229 	m_tx_tilemap->set_transparent_pen(15);
230 }
231 
232 
233 
234 /***************************************************************************
235 
236   Memory handlers
237 
238 ***************************************************************************/
239 
galivan_videoram_w(offs_t offset,uint8_t data)240 void galivan_state::galivan_videoram_w(offs_t offset, uint8_t data)
241 {
242 	m_videoram[offset] = data;
243 	m_tx_tilemap->mark_tile_dirty(offset & 0x3ff);
244 }
245 
246 /* Written through port 40 */
galivan_gfxbank_w(uint8_t data)247 void galivan_state::galivan_gfxbank_w(uint8_t data)
248 {
249 	/* bits 0 and 1 coin counters */
250 	machine().bookkeeping().coin_counter_w(0,data & 1);
251 	machine().bookkeeping().coin_counter_w(1,data & 2);
252 
253 	/* bit 2 flip screen */
254 	flip_screen_set(data & 0x04);
255 
256 	/* bit 7 selects one of two ROM banks for c000-dfff */
257 	membank("bank1")->set_entry((data & 0x80) >> 7);
258 
259 	/*  logerror("%s port 40 = %02x\n", machine().describe_context(), data); */
260 }
261 
ninjemak_gfxbank_w(uint8_t data)262 void galivan_state::ninjemak_gfxbank_w(uint8_t data)
263 {
264 	/* bits 0 and 1 coin counters */
265 	machine().bookkeeping().coin_counter_w(0,data & 1);
266 	machine().bookkeeping().coin_counter_w(1,data & 2);
267 
268 	/* bit 2 flip screen */
269 	flip_screen_set(data & 0x04);
270 
271 	/* bit 3 unknown */
272 
273 	/* bit 4 background disable flag */
274 	m_ninjemak_dispdisable = data & 0x10;
275 
276 	/* bit 5 sprite flag ??? */
277 
278 	/* bit 6, 7 ROM bank select */
279 	membank("bank1")->set_entry((data & 0xc0) >> 6);
280 
281 #if 0
282 	{
283 		char mess[80];
284 		int btz[8];
285 		int offs;
286 
287 		for (offs = 0; offs < 8; offs++) btz[offs] = (((data >> offs) & 0x01) ? 1 : 0);
288 
289 		sprintf(mess, "BK:%01X%01X S:%01X B:%01X T:%01X FF:%01X C2:%01X C1:%01X", btz[7], btz[6], btz[5], btz[4], btz[3], btz[2], btz[1], btz[0]);
290 		popmessage(mess);
291 	}
292 #endif
293 }
294 
295 
296 
297 /* Written through port 41-42 */
galivan_scrollx_w(offs_t offset,uint8_t data)298 void galivan_state::galivan_scrollx_w(offs_t offset, uint8_t data)
299 {
300 	if (offset == 1)
301 	{
302 		m_layers = data & 0xe0;
303 	}
304 	m_galivan_scrollx[offset] = data;
305 }
306 
307 /* Written through port 43-44 */
galivan_scrolly_w(offs_t offset,uint8_t data)308 void galivan_state::galivan_scrolly_w(offs_t offset, uint8_t data)
309 {
310 	m_galivan_scrolly[offset] = data;
311 }
312 
313 
314 
315 /***************************************************************************
316 
317   Display refresh
318 
319 ***************************************************************************/
320 
draw_sprites(bitmap_ind16 & bitmap,const rectangle & cliprect)321 void galivan_state::draw_sprites( bitmap_ind16 &bitmap, const rectangle &cliprect )
322 {
323 	const uint8_t *spritepalettebank = memregion("user1")->base();
324 	uint8_t *buffered_spriteram = m_spriteram->buffer();
325 	int length = m_spriteram->bytes();
326 	int flip = flip_screen();
327 	gfx_element *gfx = m_gfxdecode->gfx(2);
328 
329 	/* draw the sprites */
330 	for (int offs = 0; offs < length; offs += 4)
331 	{
332 		int code;
333 		int attr = buffered_spriteram[offs + 2];
334 		int color = (attr & 0x3c) >> 2;
335 		int flipx = attr & 0x40;
336 		int flipy = attr & 0x80;
337 		int sx, sy;
338 
339 		sx = (buffered_spriteram[offs + 3] - 0x80) + 256 * (attr & 0x01);
340 		sy = 240 - buffered_spriteram[offs];
341 		if (flip)
342 		{
343 			sx = 240 - sx;
344 			sy = 240 - sy;
345 			flipx = !flipx;
346 			flipy = !flipy;
347 		}
348 
349 //      code = buffered_spriteram[offs + 1] + ((attr & 0x02) << 7);
350 		code = buffered_spriteram[offs + 1] + ((attr & 0x06) << 7);  // for ninjemak, not sure ?
351 
352 		gfx->transpen(bitmap,cliprect,
353 				code,
354 				color + 16 * (spritepalettebank[code >> 2] & 0x0f),
355 				flipx,flipy,
356 				sx,sy,15);
357 	}
358 }
359 
360 
screen_update_galivan(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)361 uint32_t galivan_state::screen_update_galivan(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
362 {
363 	m_bg_tilemap->set_scrollx(0, m_galivan_scrollx[0] + 256 * (m_galivan_scrollx[1] & 0x07));
364 	m_bg_tilemap->set_scrolly(0, m_galivan_scrolly[0] + 256 * (m_galivan_scrolly[1] & 0x07));
365 
366 	if (m_layers & 0x40)
367 		bitmap.fill(0, cliprect);
368 	else
369 		m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
370 
371 	if (m_layers & 0x20)
372 	{
373 		if ((m_layers & 0x80) == 0)
374 		{
375 			m_tx_tilemap->draw(screen, bitmap, cliprect, 0, 0);
376 			m_tx_tilemap->draw(screen, bitmap, cliprect, 1, 0);
377 		}
378 		draw_sprites(bitmap, cliprect);
379 	}
380 	else
381 	{
382 		draw_sprites(bitmap, cliprect);
383 		if ((m_layers & 0x80) == 0)
384 		{
385 			m_tx_tilemap->draw(screen, bitmap, cliprect, 0, 0);
386 			m_tx_tilemap->draw(screen, bitmap, cliprect, 1, 0);
387 		}
388 	}
389 
390 	return 0;
391 }
392 
screen_update_ninjemak(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)393 uint32_t galivan_state::screen_update_ninjemak(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
394 {
395 	/* (scrollx[1] & 0x40) does something */
396 	m_bg_tilemap->set_scrollx(0, m_scrollx);
397 	m_bg_tilemap->set_scrolly(0, m_scrolly);
398 
399 	if (m_ninjemak_dispdisable)
400 		bitmap.fill(0, cliprect);
401 	else
402 		m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
403 
404 	draw_sprites(bitmap, cliprect);
405 	m_tx_tilemap->draw(screen, bitmap, cliprect, 0, 0);
406 	return 0;
407 }
408