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