summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/video/c45.cpp
blob: eb77aaa8215a5ba484c6bb1637f360c7bd55d7f8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
// license:BSD-3-Clause
// copyright-holders:Phil Stroffolino, Aaron Giles, Alex W. Jackson
/**************************************************************************************************************/
/*
    Land Line Buffer
    Land Generator
        0xf,0x7,0xe,0x6,0xd,0x5,0xc,0x4,
        0xb,0x3,0xa,0x2,0x9,0x1,0x8,0x0

*/

/* Preliminary!  The road circuitry is identical for all the driving games.
 *
 * There are several chunks of RAM
 *
 *  Road Tilemap:
 *      0x00000..0x0ffff    64x512 tilemap
 *
 *  Road Tiles:
 *      0x10000..0x1f9ff    16x16x2bpp tiles
 *
 *
 *  Line Attributes:
 *
 *      0x1fa00..0x1fbdf    xxx- ---- ---- ----     priority
 *                          ---- xxxx xxxx xxxx     xscroll
 *
 *      0x1fbfe             horizontal adjust?
 *                          0x0017
 *                          0x0018 (Final Lap3)
 *
 *      0x1fc00..0x1fddf    selects line in source bitmap
 *      0x1fdfe             yscroll
 *
 *      0x1fe00..0x1ffdf    ---- --xx xxxx xxxx     zoomx
 *      0x1fffd             always 0xffff 0xffff?
 */

#include "emu.h"
#include "video/c45.h"


//****************************************************************************
//  CONSTANTS
//****************************************************************************

// device type definition
DEFINE_DEVICE_TYPE(NAMCO_C45_ROAD, namco_c45_road_device, "namco_c45_road", "Namco C45 Road")


const gfx_layout namco_c45_road_device::tilelayout =
{
	ROAD_TILE_SIZE, ROAD_TILE_SIZE,
	RGN_FRAC(1,1),
	2,
	{ 0, 8 },
	{ STEP8(0, 1), STEP8(16, 1) },
	{ STEP16(0, 32) },
	0x200 // offset to next tile
};


GFXDECODE_MEMBER( namco_c45_road_device::gfxinfo )
	GFXDECODE_DEVICE_RAM( "tileram", 0, tilelayout, 0xf00, 64 )
GFXDECODE_END


void namco_c45_road_device::map(address_map &map)
{
	map(0x00000, 0x0ffff).ram().w(this, FUNC(namco_c45_road_device::tilemap_w)).share("tmapram");
	map(0x10000, 0x1f9ff).ram().w(this, FUNC(namco_c45_road_device::tileram_w)).share("tileram");
	map(0x1fa00, 0x1ffff).ram().share("lineram");
}


//-------------------------------------------------
//  namco_c45_road_device -- constructor
//-------------------------------------------------

namco_c45_road_device::namco_c45_road_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: device_t(mconfig, NAMCO_C45_ROAD, tag, owner, clock),
		device_gfx_interface(mconfig, *this, gfxinfo),
		device_memory_interface(mconfig, *this),
		m_space_config("c45", ENDIANNESS_BIG, 16, 17, 0, address_map_constructor(FUNC(namco_c45_road_device::map), this)),
		m_tmapram(*this, "tmapram"),
		m_tileram(*this, "tileram"),
		m_lineram(*this, "lineram"),
		m_transparent_color(~0)
{
}



// We need these trampolines for now because uplift_submaps()
// can't deal with address maps that contain RAM.
// We need to explicitly use device_memory_interface::space()
// because read/write handlers have a parameter called 'space'

//-------------------------------------------------
//  read -- CPU read from our address space
//-------------------------------------------------

READ16_MEMBER( namco_c45_road_device::read )
{
	return device_memory_interface::space().read_word(offset*2);
}


//-------------------------------------------------
//  write -- CPU write to our address space
//-------------------------------------------------

WRITE16_MEMBER( namco_c45_road_device::write )
{
	device_memory_interface::space().write_word(offset*2, data, mem_mask);
}


//-------------------------------------------------
//  tilemap_w -- write to tilemap RAM
//-------------------------------------------------

WRITE16_MEMBER( namco_c45_road_device::tilemap_w )
{
	COMBINE_DATA(&m_tmapram[offset]);
	m_tilemap->mark_tile_dirty(offset);
}


//-------------------------------------------------
//  tileram_w -- write to tile RAM
//-------------------------------------------------

WRITE16_MEMBER( namco_c45_road_device::tileram_w )
{
	COMBINE_DATA(&m_tileram[offset]);
	gfx(0)->mark_dirty(offset / WORDS_PER_ROAD_TILE);
}


//-------------------------------------------------
//  draw -- render to the target bitmap
//-------------------------------------------------

void namco_c45_road_device::draw(bitmap_ind16 &bitmap, const rectangle &cliprect, int pri)
{
	bitmap_ind16 &source_bitmap = m_tilemap->pixmap();
	unsigned yscroll = m_lineram[0x3fe/2];

	// loop over scanlines
	for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
	{
		// skip if we are not the right priority
		int screenx = m_lineram[y + 15];
		if (pri != ((screenx & 0xf000) >> 12))
			continue;

		// skip if we don't have a valid zoom factor
		unsigned zoomx = m_lineram[0x400/2 + y + 15] & 0x3ff;
		if (zoomx == 0)
			continue;

		// skip if we don't have a valid source increment
		unsigned sourcey = m_lineram[0x200/2 + y + 15] + yscroll;
		const uint16_t *source_gfx = &source_bitmap.pix(sourcey & (ROAD_TILEMAP_HEIGHT - 1));
		unsigned dsourcex = (ROAD_TILEMAP_WIDTH << 16) / zoomx;
		if (dsourcex == 0)
			continue;

		// mask off priority bits and sign-extend
		screenx &= 0x0fff;
		if (screenx & 0x0800)
			screenx |= ~0x7ff;

		// adjust the horizontal placement
		screenx -= 64; // needs adjustment to left

		int numpixels = (44 * ROAD_TILE_SIZE << 16) / dsourcex;
		unsigned sourcex = 0;

		// crop left
		int clip_pixels = cliprect.min_x - screenx;
		if (clip_pixels > 0)
		{
			numpixels -= clip_pixels;
			sourcex += dsourcex*clip_pixels;
			screenx = cliprect.min_x;
		}

		// crop right
		clip_pixels = (screenx + numpixels) - (cliprect.max_x + 1);
		if (clip_pixels > 0)
			numpixels -= clip_pixels;

		// TBA: work out palette mapping for Final Lap, Suzuka

		// BUT: support transparent color for Thunder Ceptor
		uint16_t *dest = &bitmap.pix(y);
		if (m_transparent_color != ~0)
		{
			while (numpixels-- > 0)
			{
				int pen = source_gfx[sourcex >> 16];
				if (palette().pen_indirect(pen) != m_transparent_color)
				{
					if (m_clut != nullptr)
						pen = (pen & ~0xff) | m_clut[pen & 0xff];
					dest[screenx] = pen;
				}
				screenx++;
				sourcex += dsourcex;
			}
		}
		else
		{
			while (numpixels-- > 0)
			{
				int pen = source_gfx[sourcex >> 16];
				if (m_clut != nullptr)
					pen = (pen & ~0xff) | m_clut[pen & 0xff];
				dest[screenx++] = pen;
				sourcex += dsourcex;
			}
		}
	}
}


//-------------------------------------------------
//  device_start -- device startup
//-------------------------------------------------

void namco_c45_road_device::device_start()
{
	if (memregion("clut") != nullptr)
		m_clut = memregion("clut")->base();

	// create a tilemap for the road
	m_tilemap = &machine().tilemap().create(*this, tilemap_get_info_delegate(FUNC(namco_c45_road_device::get_road_info), this),
		TILEMAP_SCAN_ROWS, ROAD_TILE_SIZE, ROAD_TILE_SIZE, ROAD_COLS, ROAD_ROWS);
}


//-------------------------------------------------
//  memory_space_config - return a description of
//  any address spaces owned by this device
//-------------------------------------------------

device_memory_interface::space_config_vector namco_c45_road_device::memory_space_config() const
{
	return space_config_vector {
		std::make_pair(0, &m_space_config)
	};
}


//-------------------------------------------------
//  get_road_info -- tilemap callback
//-------------------------------------------------

TILE_GET_INFO_MEMBER( namco_c45_road_device::get_road_info )
{
	// ------xx xxxxxxxx tile number
	// xxxxxx-- -------- palette select
	uint16_t data = m_tmapram[tile_index];
	int tile = data & 0x3ff;
	int color = data >> 10;
	SET_TILE_INFO_MEMBER(0, tile, color, 0);
}