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