1 // license:BSD-3-Clause
2 // copyright-holders:Bryan McPhail
3 /***************************************************************************
4
5 Lemmings video emulation - Bryan McPhail, mish@tendril.co.uk
6
7 *********************************************************************
8
9 There are two sets of sprites, the combination of custom chips 52 & 71.
10 There is a background pixel layer implemented with discrete logic
11 rather than a custom chip and a foreground VRAM tilemap layer that the
12 game mostly uses as a pixel layer (the vram format is arranged as
13 sequential pixels, rather than sequential characters).
14
15 ***************************************************************************/
16
17 #include "emu.h"
18 #include "includes/lemmings.h"
19
20 #include <algorithm>
21
22 /******************************************************************************/
23
TILE_GET_INFO_MEMBER(lemmings_state::get_tile_info)24 TILE_GET_INFO_MEMBER(lemmings_state::get_tile_info)
25 {
26 uint16_t tile = m_vram_data[tile_index];
27
28 tileinfo.set(2,
29 tile&0x7ff,
30 (tile>>12)&0xf,
31 0);
32 }
33
video_start()34 void lemmings_state::video_start()
35 {
36 m_vram_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(lemmings_state::get_tile_info)), TILEMAP_SCAN_COLS, 8, 8, 64, 32);
37
38 m_vram_tilemap->set_transparent_pen(0);
39 m_bitmap0.fill(0x100);
40
41 m_vram_buffer = make_unique_clear<uint8_t[]>(2048 * 64); // 64 bytes per VRAM character
42 m_gfxdecode->gfx(2)->set_source(m_vram_buffer.get());
43
44 m_sprgen[0]->alloc_sprite_bitmap();
45 m_sprgen[1]->alloc_sprite_bitmap();
46
47 m_sprite_triple_buffer[0] = make_unique_clear<uint16_t[]>(0x800/2);
48 m_sprite_triple_buffer[1] = make_unique_clear<uint16_t[]>(0x800/2);
49
50 save_item(NAME(m_bitmap0));
51 save_pointer(NAME(m_vram_buffer), 2048 * 64);
52 save_pointer(NAME(m_sprite_triple_buffer[0]), 0x800/2, 0);
53 save_pointer(NAME(m_sprite_triple_buffer[1]), 0x800/2, 1);
54 }
55
WRITE_LINE_MEMBER(lemmings_state::screen_vblank_lemmings)56 WRITE_LINE_MEMBER(lemmings_state::screen_vblank_lemmings)
57 {
58 // rising edge
59 if (state)
60 {
61 for (int chip = 0; chip < 2; chip++)
62 std::copy_n(&m_spriteram[chip]->buffer()[0], 0x800/2, &m_sprite_triple_buffer[chip][0]);
63 }
64 }
65
66 /******************************************************************************/
67
68 // RAM based
lemmings_pixel_0_w(offs_t offset,uint16_t data,uint16_t mem_mask)69 void lemmings_state::lemmings_pixel_0_w(offs_t offset, uint16_t data, uint16_t mem_mask)
70 {
71 int const old = m_pixel_data[0][offset];
72 COMBINE_DATA(&m_pixel_data[0][offset]);
73 int const src = m_pixel_data[0][offset];
74 if (old == src)
75 return;
76
77 int const sy = (offset << 1) >> 11;
78 int const sx = (offset << 1) & 0x7ff;
79
80 if (sx > 2047 || sy > 255)
81 return;
82
83 m_bitmap0.pix(sy, sx + 0) = ((src >> 8) & 0xf) | 0x100;
84 m_bitmap0.pix(sy, sx + 1) = ((src >> 0) & 0xf) | 0x100;
85 }
86
87 // RAM based tiles for the FG tilemap
lemmings_pixel_1_w(offs_t offset,uint16_t data,uint16_t mem_mask)88 void lemmings_state::lemmings_pixel_1_w(offs_t offset, uint16_t data, uint16_t mem_mask)
89 {
90 int sx, sy, src, tile;
91
92 COMBINE_DATA(&m_pixel_data[1][offset]);
93 src = m_pixel_data[1][offset];
94
95 sy = (offset << 1) >> 9;
96 sx = (offset << 1) & 0x1ff;
97
98 /* Copy pixel to buffer for easier decoding later */
99 tile = ((sx / 8) * 32) + (sy / 8);
100 m_gfxdecode->gfx(2)->mark_dirty(tile);
101 m_vram_buffer[(tile * 64) + ((sx & 7)) + ((sy & 7) * 8)] = (src >> 8) & 0xf;
102
103 sx += 1; /* Update both pixels in the word */
104 m_vram_buffer[(tile * 64) + ((sx & 7)) + ((sy & 7) * 8)] = (src >> 0) & 0xf;
105 }
106
lemmings_vram_w(offs_t offset,uint16_t data,uint16_t mem_mask)107 void lemmings_state::lemmings_vram_w(offs_t offset, uint16_t data, uint16_t mem_mask)
108 {
109 COMBINE_DATA(&m_vram_data[offset]);
110 m_vram_tilemap->mark_tile_dirty(offset);
111 }
112
113
lemmings_copy_bitmap(bitmap_rgb32 & bitmap,int * xscroll,int * yscroll,const rectangle & cliprect)114 void lemmings_state::lemmings_copy_bitmap(bitmap_rgb32& bitmap, int* xscroll, int* yscroll, const rectangle& cliprect)
115 {
116 pen_t const *const paldata = m_palette->pens();
117
118 for (int y=cliprect.top(); y<cliprect.bottom();y++)
119 {
120 uint32_t *const dst = &bitmap.pix(y,0);
121
122 for (int x=cliprect.left(); x<cliprect.right();x++)
123 {
124 uint16_t const src = m_bitmap0.pix((y-*yscroll)&0xff,(x-*xscroll)&0x7ff);
125
126 if (src!=0x100)
127 dst[x] = paldata[src];
128 }
129 }
130 }
131
screen_update_lemmings(screen_device & screen,bitmap_rgb32 & bitmap,const rectangle & cliprect)132 uint32_t lemmings_state::screen_update_lemmings(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
133 {
134 int x1 = -m_control_data[0];
135 int x0 = -m_control_data[2];
136 int y = 0;
137 rectangle rect(0, 0, cliprect.top(), cliprect.bottom());
138
139 // sprites are flipped relative to tilemaps
140 m_sprgen[0]->set_flip_screen(true);
141 m_sprgen[1]->set_flip_screen(true);
142 m_sprgen[0]->draw_sprites(bitmap, cliprect, m_sprite_triple_buffer[1].get(), 0x400);
143 m_sprgen[1]->draw_sprites(bitmap, cliprect, m_sprite_triple_buffer[0].get(), 0x400);
144
145 bitmap.fill(m_palette->black_pen(), cliprect);
146 m_sprgen[0]->inefficient_copy_sprite_bitmap(bitmap, cliprect, 0x0800, 0x0800, 0x300, 0xff);
147
148 /* Pixel layer can be windowed in hardware (two player mode) */
149 if ((m_control_data[6] & 2) == 0)
150 {
151 lemmings_copy_bitmap(bitmap, &x1, &y, cliprect);
152 }
153 else
154 {
155 rect.setx(0, 159);
156 lemmings_copy_bitmap(bitmap, &x0, &y, rect);
157
158 rect.setx(160, 319);
159 lemmings_copy_bitmap(bitmap, &x1, &y, rect);
160 }
161
162 m_sprgen[1]->inefficient_copy_sprite_bitmap(bitmap, cliprect, 0x0800, 0x0800, 0x200, 0xff);
163 m_sprgen[0]->inefficient_copy_sprite_bitmap(bitmap, cliprect, 0x0000, 0x0800, 0x300, 0xff);
164 m_vram_tilemap->draw(screen, bitmap, cliprect, 0, 0);
165 m_sprgen[1]->inefficient_copy_sprite_bitmap(bitmap, cliprect, 0x0000, 0x0800, 0x200, 0xff);
166 return 0;
167 }
168