1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles
3 /***************************************************************************
4 
5     The Game Room Lethal Justice hardware
6 
7 ***************************************************************************/
8 
9 #include "emu.h"
10 #include "includes/lethalj.h"
11 
12 
13 #define BLITTER_SOURCE_WIDTH        1024
14 #define BLITTER_DEST_WIDTH          512
15 #define BLITTER_DEST_HEIGHT         512
16 
17 
18 /*************************************
19  *
20  *  Compute X/Y coordinates
21  *
22  *************************************/
23 
get_crosshair_xy(int player,int * x,int * y)24 inline void lethalj_state::get_crosshair_xy(int player, int *x, int *y)
25 {
26 	const rectangle &visarea = m_screen->visible_area();
27 	int width = visarea.width();
28 	int height = visarea.height();
29 
30 	if (player)
31 	{
32 		*x = ((m_light1_x.read_safe(0) & 0xff) * width) / 255;
33 		*y = ((m_light1_y.read_safe(0) & 0xff) * height) / 255;
34 	}
35 	else
36 	{
37 		*x = ((m_light0_x.read_safe(0) & 0xff) * width) / 255;
38 		*y = ((m_light0_y.read_safe(0) & 0xff) * height) / 255;
39 	}
40 }
41 
42 
43 
44 /*************************************
45  *
46  *  Gun input handling
47  *
48  *************************************/
49 
lethalj_gun_r(offs_t offset)50 uint16_t lethalj_state::lethalj_gun_r(offs_t offset)
51 {
52 	uint16_t result = 0;
53 	int beamx, beamy;
54 
55 	switch (offset)
56 	{
57 		case 4:
58 		case 5:
59 			/* latch the crosshair position */
60 			get_crosshair_xy(offset - 4, &beamx, &beamy);
61 			m_gunx = beamx;
62 			m_guny = beamy;
63 			m_blank_palette = 1;
64 			break;
65 
66 		case 6:
67 			result = m_gunx / 2;
68 			break;
69 
70 		case 7:
71 			result = m_guny + 4;
72 			break;
73 	}
74 /*  logerror("%s:lethalj_gun_r(%d) = %04X\n", machine().describe_context(), offset, result); */
75 	return result;
76 }
77 
78 
79 
80 /*************************************
81  *
82  *  video startup
83  *
84  *************************************/
85 
video_start()86 void lethalj_state::video_start()
87 {
88 	/* allocate video RAM for screen */
89 	m_screenram = std::make_unique<uint16_t[]>(BLITTER_DEST_WIDTH * BLITTER_DEST_HEIGHT);
90 
91 	/* predetermine blitter info */
92 	m_blitter_rows = m_blitter_base.length() / BLITTER_SOURCE_WIDTH;
93 
94 	m_gen_ext1_int_timer = timer_alloc(TIMER_GEN_EXT1_INT);
95 }
96 
97 
98 
99 /*************************************
100  *
101  *  Memory maps
102  *
103  *************************************/
104 
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)105 void lethalj_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
106 {
107 	switch (id)
108 	{
109 	case TIMER_GEN_EXT1_INT:
110 		m_maincpu->set_input_line(0, ASSERT_LINE);
111 		break;
112 	default:
113 		throw emu_fatalerror("Unknown id in lethalj_state::device_timer");
114 	}
115 }
116 
117 
do_blit()118 void lethalj_state::do_blit()
119 {
120 	int dsty = (int16_t)m_blitter_data[1];
121 	int srcx = (uint16_t)m_blitter_data[2];
122 	int srcy = (uint16_t)(m_blitter_data[3] + 1);
123 	int width = (uint16_t)m_blitter_data[5];
124 	int dstx = (int16_t)m_blitter_data[6];
125 	int height = (uint16_t)m_blitter_data[7];
126 	int y;
127 /*
128     logerror("blitter data = %04X %04X %04X %04X %04X %04X %04X %04X\n",
129             m_blitter_data[0], m_blitter_data[1], m_blitter_data[2], m_blitter_data[3],
130             m_blitter_data[4], m_blitter_data[5], m_blitter_data[6], m_blitter_data[7]);
131 */
132 	/* loop over Y coordinates */
133 	for (y = 0; y <= height; y++, srcy++, dsty++)
134 	{
135 		/* clip in Y */
136 		if (dsty >= 0 && dsty < BLITTER_DEST_HEIGHT/2)
137 		{
138 			uint16_t *source = m_blitter_base + ((srcy % m_blitter_rows) << 10);
139 			uint16_t *dest = m_screenram.get() + ((dsty + ((m_vispage ^ 1) << 8)) << 9);
140 			int sx = srcx;
141 			int dx = dstx;
142 			int x;
143 
144 			/* loop over X coordinates */
145 			for (x = 0; x <= width; x++, sx++, dx++)
146 			{
147 				dx &= 0x1ff;
148 
149 				int pix = source[sx & 0x3ff];
150 				if (pix)
151 					dest[dx] = pix;
152 
153 			}
154 		}
155 	}
156 }
157 
158 
blitter_w(offs_t offset,uint16_t data,uint16_t mem_mask)159 void lethalj_state::blitter_w(offs_t offset, uint16_t data, uint16_t mem_mask)
160 {
161 	/* combine the data */
162 	COMBINE_DATA(&m_blitter_data[offset]);
163 
164 	/* blit on a write to offset 7, and signal an IRQ */
165 	if (offset == 7)
166 	{
167 		if (m_blitter_data[6] == 2 && m_blitter_data[7] == 2)
168 			m_vispage ^= 1;
169 		else
170 			do_blit();
171 
172 		m_gen_ext1_int_timer->adjust(attotime::from_hz(XTAL(32'000'000)) * ((m_blitter_data[5] + 1) * (m_blitter_data[7] + 1)));
173 	}
174 
175 	/* clear the IRQ on offset 0 */
176 	else if (offset == 0)
177 		m_maincpu->set_input_line(0, CLEAR_LINE);
178 }
179 
180 
181 
182 /*************************************
183  *
184  *  video update
185  *
186  *************************************/
187 
TMS340X0_SCANLINE_IND16_CB_MEMBER(lethalj_state::scanline_update)188 TMS340X0_SCANLINE_IND16_CB_MEMBER(lethalj_state::scanline_update)
189 {
190 	uint16_t const *const src = &m_screenram[(m_vispage << 17) | ((params->rowaddr << 9) & 0x3fe00)];
191 	uint16_t *const dest = &bitmap.pix(scanline);
192 	int coladdr = params->coladdr << 1;
193 
194 	/* blank palette: fill with white */
195 	if (m_blank_palette)
196 	{
197 		for (int x = params->heblnk; x < params->hsblnk; x++)
198 			dest[x] = 0x7fff;
199 		if (scanline == screen.visible_area().max_y)
200 			m_blank_palette = 0;
201 	}
202 	else
203 	{
204 		/* copy the non-blanked portions of this scanline */
205 		for (int x = params->heblnk; x < params->hsblnk; x++)
206 			dest[x] = src[coladdr++ & 0x1ff] & 0x7fff;
207 	}
208 }
209