1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles
3 /*************************************************************************
4 
5     Driver for Midway Zeus games
6 
7 **************************************************************************/
8 
9 #include "emu.h"
10 #include "includes/midzeus.h"
11 #include "video/rgbutil.h"
12 
13 
14 
15 /*************************************
16  *
17  *  Constants
18  *
19  *************************************/
20 
21 #define DUMP_WAVE_RAM       0
22 
23 #define WAVERAM0_WIDTH      512
24 #define WAVERAM0_HEIGHT     2048
25 
26 #define WAVERAM1_WIDTH      512
27 #define WAVERAM1_HEIGHT     512
28 
29 #define BLEND_OPAQUE1       0x00000000
30 #define BLEND_OPAQUE2       0x4b23cb00
31 #define BLEND_OPAQUE3       0x4b23dd00
32 #define BLEND_OPAQUE4       0x00004800
33 #define BLEND_OPAQUE5       0xdd23dd00
34 #define BLEND_ADD1          0x40b68800
35 #define BLEND_ADD2          0xc9b78800
36 #define BLEND_MUL1          0x4093c800
37 
38 
39 /*************************************
40  *
41  *  Function prototypes
42  *
43  *************************************/
44 
45 static inline uint8_t get_texel_4bit(const void *base, int y, int x, int width);
46 static inline uint8_t get_texel_alt_4bit(const void *base, int y, int x, int width);
47 static inline uint8_t get_texel_8bit(const void *base, int y, int x, int width);
48 static inline uint8_t get_texel_alt_8bit(const void *base, int y, int x, int width);
49 
50 
51 /*************************************
52  *
53  *  Macros
54  *
55  *************************************/
56 
57 #define WAVERAM_BLOCK0(blocknum)                ((void *)((uint8_t *)m_waveram[0].get() + 8 * (blocknum)))
58 #define WAVERAM_BLOCK1(blocknum)                ((void *)((uint8_t *)m_waveram[1].get() + 8 * (blocknum)))
59 
60 #define WAVERAM_PTR8(base, bytenum)             ((uint8_t *)(base) + BYTE4_XOR_LE(bytenum))
61 #define WAVERAM_READ8(base, bytenum)            (*WAVERAM_PTR8(base, bytenum))
62 #define WAVERAM_WRITE8(base, bytenum, data)     do { *WAVERAM_PTR8(base, bytenum) = (data); } while (0)
63 
64 #define WAVERAM_PTR16(base, wordnum)            ((uint16_t *)(base) + BYTE_XOR_LE(wordnum))
65 #define WAVERAM_READ16(base, wordnum)           (*WAVERAM_PTR16(base, wordnum))
66 #define WAVERAM_WRITE16(base, wordnum, data)    do { *WAVERAM_PTR16(base, wordnum) = (data); } while (0)
67 
68 #define WAVERAM_PTR32(base, dwordnum)           ((uint32_t *)(base) + (dwordnum))
69 #define WAVERAM_READ32(base, dwordnum)          (*WAVERAM_PTR32(base, dwordnum))
70 #define WAVERAM_WRITE32(base, dwordnum, data)   do { *WAVERAM_PTR32(base, dwordnum) = (data); } while (0)
71 
72 #define PIXYX_TO_WORDNUM(y, x)                  (((y) << 10) | (((x) & 0x1fe) << 1) | ((x) & 1))
73 #define DEPTHYX_TO_WORDNUM(y, x)                (PIXYX_TO_WORDNUM(y, x) | 2)
74 
75 #define WAVERAM_PTRPIX(base, y, x)              WAVERAM_PTR16(base, PIXYX_TO_WORDNUM(y, x))
76 #define WAVERAM_READPIX(base, y, x)             (*WAVERAM_PTRPIX(base, y, x))
77 #define WAVERAM_WRITEPIX(base, y, x, color)     do { *WAVERAM_PTRPIX(base, y, x) = (color);  } while (0)
78 
79 #define WAVERAM_PTRDEPTH(base, y, x)            WAVERAM_PTR16(base, DEPTHYX_TO_WORDNUM(y, x))
80 #define WAVERAM_READDEPTH(base, y, x)           (*WAVERAM_PTRDEPTH(base, y, x))
81 #define WAVERAM_WRITEDEPTH(base, y, x, color)   do { *WAVERAM_PTRDEPTH(base, y, x) = (color);  } while (0)
82 
83 
84 
85 /*************************************
86  *
87  *  Inlines for block addressing
88  *
89  *************************************/
90 
waveram0_ptr_from_block_addr(uint32_t addr)91 inline void *midzeus_state::waveram0_ptr_from_block_addr(uint32_t addr)
92 {
93 	uint32_t blocknum = (addr % WAVERAM0_WIDTH) + ((addr >> 12) % WAVERAM0_HEIGHT) * WAVERAM0_WIDTH;
94 	return WAVERAM_BLOCK0(blocknum);
95 }
96 
waveram0_ptr_from_expanded_addr(uint32_t addr)97 inline void *midzeus_state::waveram0_ptr_from_expanded_addr(uint32_t addr)
98 {
99 	uint32_t blocknum = (addr % WAVERAM0_WIDTH) + ((addr >> 16) % WAVERAM0_HEIGHT) * WAVERAM0_WIDTH;
100 	return WAVERAM_BLOCK0(blocknum);
101 }
102 
waveram1_ptr_from_expanded_addr(uint32_t addr)103 inline void *midzeus_state::waveram1_ptr_from_expanded_addr(uint32_t addr)
104 {
105 	uint32_t blocknum = (addr % WAVERAM1_WIDTH) + ((addr >> 16) % WAVERAM1_HEIGHT) * WAVERAM1_WIDTH;
106 	return WAVERAM_BLOCK1(blocknum);
107 }
108 
waveram0_ptr_from_texture_addr(uint32_t addr,int width)109 inline void *midzeus_state::waveram0_ptr_from_texture_addr(uint32_t addr, int width)
110 {
111 	uint32_t blocknum = (((addr & ~1) * width) / 8) % (WAVERAM0_WIDTH * WAVERAM0_HEIGHT);
112 	return WAVERAM_BLOCK0(blocknum);
113 }
114 
115 
116 
117 /*************************************
118  *
119  *  Inlines for rendering
120  *
121  *************************************/
122 
waveram_plot_depth(int y,int x,uint16_t color,uint16_t depth)123 inline void midzeus_state::waveram_plot_depth(int y, int x, uint16_t color, uint16_t depth)
124 {
125 	if (m_zeus_cliprect.contains(x, y))
126 	{
127 		WAVERAM_WRITEPIX(m_zeus_renderbase, y, x, color);
128 		WAVERAM_WRITEDEPTH(m_zeus_renderbase, y, x, depth);
129 	}
130 }
131 
132 #ifdef UNUSED_FUNCTION
waveram_plot(int y,int x,uint16_t color)133 inline void midzeus_state::waveram_plot(int y, int x, uint16_t color)
134 {
135 	if (m_zeus_cliprect.contains(x, y))
136 		WAVERAM_WRITEPIX(m_zeus_renderbase, y, x, color);
137 }
138 
waveram_plot_check_depth(int y,int x,uint16_t color,uint16_t depth)139 inline void midzeus_state::waveram_plot_check_depth(int y, int x, uint16_t color, uint16_t depth)
140 {
141 	if (m_zeus_cliprect.contains(x, y))
142 	{
143 		uint16_t *depthptr = WAVERAM_PTRDEPTH(m_zeus_renderbase, y, x);
144 		if (depth <= *depthptr)
145 		{
146 			WAVERAM_WRITEPIX(m_zeus_renderbase, y, x, color);
147 			*depthptr = depth;
148 		}
149 	}
150 }
151 
waveram_plot_check_depth_nowrite(int y,int x,uint16_t color,uint16_t depth)152 inline void midzeus_state::waveram_plot_check_depth_nowrite(int y, int x, uint16_t color, uint16_t depth)
153 {
154 	if (m_zeus_cliprect.contains(x, y))
155 	{
156 		uint16_t *depthptr = WAVERAM_PTRDEPTH(m_zeus_renderbase, y, x);
157 		if (depth <= *depthptr)
158 			WAVERAM_WRITEPIX(m_zeus_renderbase, y, x, color);
159 	}
160 }
161 #endif
162 
163 
164 /*************************************
165  *
166  *  Inlines for texel accesses
167  *
168  *************************************/
169 
170 // 4x2 block size
get_texel_4bit(const void * base,int y,int x,int width)171 static inline uint8_t get_texel_4bit(const void *base, int y, int x, int width)
172 {
173 	uint32_t byteoffs = (y / 2) * (width * 2) + ((x / 8) << 3) + ((y & 1) << 2) + ((x / 2) & 3);
174 	return (WAVERAM_READ8(base, byteoffs) >> (4 * (x & 1))) & 0x0f;
175 }
176 
get_texel_8bit(const void * base,int y,int x,int width)177 static inline uint8_t get_texel_8bit(const void *base, int y, int x, int width)
178 {
179 	uint32_t byteoffs = (y / 2) * (width * 2) + ((x / 4) << 3) + ((y & 1) << 2) + (x & 3);
180 	return WAVERAM_READ8(base, byteoffs);
181 }
182 
183 // 2x2 block size
get_texel_alt_4bit(const void * base,int y,int x,int width)184 static inline uint8_t get_texel_alt_4bit(const void *base, int y, int x, int width)
185 {
186 	uint32_t byteoffs = (y / 4) * (width * 4) + ((x / 4) << 3) + ((y & 3) << 1) + ((x / 2) & 1);
187 	return (WAVERAM_READ8(base, byteoffs) >> (4 * (x & 1))) & 0x0f;
188 }
189 
get_texel_alt_8bit(const void * base,int y,int x,int width)190 static inline uint8_t get_texel_alt_8bit(const void *base, int y, int x, int width)
191 {
192 	uint32_t byteoffs =  (y / 4) * (width * 4) + ((x / 2) << 3) + ((y & 3) << 1) + (x & 1);
193 	return WAVERAM_READ8(base, byteoffs);
194 }
195 
196 /*************************************
197  *
198  *  Video startup
199  *
200  *************************************/
201 
midzeus_renderer(midzeus_state & state)202 midzeus_renderer::midzeus_renderer(midzeus_state &state)
203 	: poly_manager<float, mz_poly_extra_data, 4, 10000>(state.machine()),
204 		m_state(state)
205 {}
206 
video_start()207 void midzeus_state::video_start()
208 {
209 	/* allocate memory for "wave" RAM */
210 	m_waveram[0] = std::make_unique<uint32_t[]>(WAVERAM0_WIDTH * WAVERAM0_HEIGHT * 8/4);
211 	m_waveram[1] = std::make_unique<uint32_t[]>(WAVERAM1_WIDTH * WAVERAM1_HEIGHT * 8/4);
212 
213 	/* initialize a 5-5-5 palette */
214 	for (int i = 0; i < 32768; i++)
215 		m_palette->set_pen_color(i, pal5bit(i >> 10), pal5bit(i >> 5), pal5bit(i >> 0));
216 
217 	/* initialize polygon engine */
218 	m_poly = std::make_unique<midzeus_renderer>(*this);
219 
220 	/* we need to cleanup on exit */
221 	machine().add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(&midzeus_state::exit_handler, this));
222 
223 	m_yoffs = 0;
224 	m_texel_width = 256;
225 	m_zeus_renderbase = m_waveram[1].get();
226 
227 	/* state saving */
228 	save_item(NAME(m_zeus_fifo));
229 	save_item(NAME(m_zeus_fifo_words));
230 	save_item(NAME(m_zeus_matrix));
231 	save_item(NAME(m_zeus_point));
232 	save_item(NAME(m_zeus_light));
233 	save_item(NAME(m_zeus_palbase));
234 	save_item(NAME(m_zeus_objdata));
235 	save_item(NAME(m_zeus_cliprect.min_x));
236 	save_item(NAME(m_zeus_cliprect.max_x));
237 	save_item(NAME(m_zeus_cliprect.min_y));
238 	save_item(NAME(m_zeus_cliprect.max_y));
239 	save_pointer(NAME(m_waveram[0]), WAVERAM0_WIDTH * WAVERAM0_HEIGHT * 8 / sizeof(m_waveram[0][0]));
240 	save_pointer(NAME(m_waveram[1]), WAVERAM1_WIDTH * WAVERAM1_HEIGHT * 8 / sizeof(m_waveram[1][0]));
241 
242 	/* hack */
243 	m_is_mk4b = strcmp(machine().system().name, "mk4b") == 0;
244 }
245 
246 
exit_handler()247 void midzeus_state::exit_handler()
248 {
249 #if DUMP_WAVE_RAM
250 	FILE *f = fopen("waveram.dmp", "w");
251 	int i;
252 
253 	for (i = 0; i < WAVERAM0_WIDTH * WAVERAM0_HEIGHT; i++)
254 	{
255 		if (i % 4 == 0) fprintf(f, "%03X%03X: ", i / WAVERAM0_WIDTH, i % WAVERAM0_WIDTH);
256 		fprintf(f, " %08X %08X ",
257 			WAVERAM_READ32(waveram[0], i*2+0),
258 			WAVERAM_READ32(waveram[0], i*2+1));
259 		if (i % 4 == 3) fprintf(f, "\n");
260 	}
261 	fclose(f);
262 #endif
263 }
264 
265 
266 
267 /*************************************
268  *
269  *  Video update
270  *
271  *************************************/
272 
screen_update(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)273 uint32_t midzeus_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
274 {
275 	m_poly->wait("VIDEO_UPDATE");
276 
277 	/* normal update case */
278 	if (!machine().input().code_pressed(KEYCODE_V))
279 	{
280 		const void *base = waveram1_ptr_from_expanded_addr(m_zeusbase[0xcc]);
281 		int xoffs = screen.visible_area().min_x;
282 		for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
283 		{
284 			uint16_t *const dest = &bitmap.pix(y);
285 			for (int x = cliprect.min_x; x <= cliprect.max_x; x++)
286 				dest[x] = WAVERAM_READPIX(base, y, x - xoffs) & 0x7fff;
287 		}
288 	}
289 
290 	/* waveram drawing case */
291 	else
292 	{
293 		const void *base;
294 
295 		if (machine().input().code_pressed(KEYCODE_DOWN)) m_yoffs += machine().input().code_pressed(KEYCODE_LSHIFT) ? 0x40 : 1;
296 		if (machine().input().code_pressed(KEYCODE_UP)) m_yoffs -= machine().input().code_pressed(KEYCODE_LSHIFT) ? 0x40 : 1;
297 		if (machine().input().code_pressed(KEYCODE_LEFT) && m_texel_width > 4) { m_texel_width >>= 1; while (machine().input().code_pressed(KEYCODE_LEFT)) ; }
298 		if (machine().input().code_pressed(KEYCODE_RIGHT) && m_texel_width < 512) { m_texel_width <<= 1; while (machine().input().code_pressed(KEYCODE_RIGHT)) ; }
299 
300 		if (m_yoffs < 0) m_yoffs = 0;
301 		base = waveram0_ptr_from_block_addr(m_yoffs << 12);
302 
303 		for (int y = cliprect.min_y; y <= cliprect.max_y; y++)
304 		{
305 			uint16_t *const dest = &bitmap.pix(y);
306 			for (int x = cliprect.min_x; x <= cliprect.max_x; x++)
307 			{
308 				uint8_t const tex = get_texel_8bit(base, y, x, m_texel_width);
309 				dest[x] = (tex << 8) | tex;
310 			}
311 		}
312 		popmessage("offs = %06X", m_yoffs << 12);
313 	}
314 
315 	return 0;
316 }
317 
318 
319 
320 /*************************************
321  *
322  *  Core read handler
323  *
324  *************************************/
325 
zeus_r(offs_t offset)326 uint32_t midzeus_state::zeus_r(offs_t offset)
327 {
328 	bool logit = (offset < 0xb0 || offset > 0xb7);
329 	uint32_t result = m_zeusbase[offset & ~1];
330 
331 	switch (offset & ~1)
332 	{
333 		case 0xf0:
334 			result = m_screen->hpos();
335 			logit = 0;
336 			break;
337 
338 		case 0xf2:
339 			result = m_screen->vpos();
340 			logit = 0;
341 			break;
342 
343 		case 0xf4:
344 			result = 6;
345 			if (m_screen->vblank())
346 				result |= 0x800;
347 			logit = 0;
348 			break;
349 
350 		case 0xf6:      // status -- they wait for this & 9 == 0
351 			// value & $9600 must == $9600 to pass Zeus system test
352 			result = 0x9600;
353 			if (m_zeusbase[0xb6] == 0x80040000)
354 				result |= 1;
355 			logit = 0;
356 			break;
357 	}
358 
359 	/* 32-bit mode */
360 	if (m_zeusbase[0x80] & 0x00020000)
361 	{
362 		if (offset & 1)
363 			result >>= 16;
364 		if (logit)
365 		{
366 			if (offset & 1)
367 				logerror("%06X:zeus32_r(%02X) = %08X -- unexpected in 32-bit mode\n", m_maincpu->pc(), offset, result);
368 			else if (offset != 0xe0)
369 				logerror("%06X:zeus32_r(%02X) = %08X\n", m_maincpu->pc(), offset, result);
370 			else
371 				logerror("%06X:zeus32_r(%02X) = %08X\n", m_maincpu->pc(), offset, result);
372 		}
373 	}
374 
375 	/* 16-bit mode */
376 	else
377 	{
378 		if (offset & 1)
379 			result >>= 16;
380 		else
381 			result &= 0xffff;
382 		if (logit)
383 			logerror("%06X:zeus16_r(%02X) = %04X\n", m_maincpu->pc(), offset, result);
384 	}
385 	return result;
386 }
387 
388 
389 
390 /*************************************
391  *
392  *  Core write handler
393  *
394  *************************************/
395 
zeus_w(offs_t offset,uint32_t data)396 void midzeus_state::zeus_w(offs_t offset, uint32_t data)
397 {
398 	bool logit = m_zeus_enable_logging || ((offset < 0xb0 || offset > 0xb7) && (offset < 0xe0 || offset > 0xe1));
399 
400 	if (logit)
401 		logerror("%06X:zeus_w", m_maincpu->pc());
402 
403 	/* 32-bit mode */
404 	if (m_zeusbase[0x80] & 0x00020000)
405 		zeus_register32_w(offset, data, logit);
406 
407 	/* 16-bit mode */
408 	else
409 		zeus_register16_w(offset, data, logit);
410 }
411 
412 
413 
414 /*************************************
415  *
416  *  Handle writes to an internal
417  *  pointer register
418  *
419  *************************************/
420 
zeus_pointer_w(uint32_t which,uint32_t data,bool logit)421 void midzeus_state::zeus_pointer_w(uint32_t which, uint32_t data, bool logit)
422 {
423 	switch (which & 0xffffff)
424 	{
425 		case 0x008000:
426 		case 0x018000:
427 			if (logit)
428 				logerror(" -- setptr(objdata)\n");
429 			m_zeus_objdata = data;
430 			break;
431 
432 		// case 0x00c040: -- set in model data in invasn
433 		case 0x00c040:
434 			if (logit)
435 				logerror(" -- setptr(palbase)\n");
436 			m_zeus_palbase = data;
437 			break;
438 
439 		case 0x02c0f0:
440 			if (logit)
441 				logerror(" -- setptr(unkbase)\n");
442 			m_zeus_unkbase = data;
443 			break;
444 
445 
446 		// case 0x004040: -- set via FIFO command in mk4 (len=02)
447 
448 		// case 0x02c0f0: -- set in model data in mk4 (len=0f)
449 		// case 0x03c0f0: -- set via FIFO command in mk4 (len=00)
450 
451 		// case 0x02c0e7: -- set via FIFO command in mk4 (len=08)
452 
453 		// case 0x04c09c: -- set via FIFO command in mk4 (len=08)
454 
455 		// case 0x05c0a5: -- set via FIFO command in mk4 (len=21)
456 		// case 0x80c0a5: -- set via FIFO command in mk4 (len=3f)
457 		// case 0x81c0a5: -- set via FIFO command in mk4 (len=35)
458 		// case 0x82c0a5: -- set via FIFO command in mk4 (len=41)
459 
460 
461 		// case 0x00c0f0: -- set via FIFO command in invasn (len=0f)
462 
463 		// case 0x00c0b0: -- set via FIFO command in invasn (len=3f) -- seems to be the same as c0a5
464 		// case 0x05c0b0: -- set via FIFO command in invasn (len=21)
465 
466 		// case 0x00c09c: -- set via FIFO command in invasn (len=06)
467 
468 		// case 0x00c0a3: -- set via FIFO command in invasn (len=0a)
469 
470 
471 		default:
472 			if (logit)
473 				logerror(" -- setptr(%06X)\n", which & 0xffffff);
474 			break;
475 	}
476 
477 	if (logit)
478 		log_waveram(data);
479 }
480 
481 
482 
483 /*************************************
484  *
485  *  Handle register writes
486  *
487  *************************************/
488 
zeus_register16_w(offs_t offset,uint16_t data,bool logit)489 void midzeus_state::zeus_register16_w(offs_t offset, uint16_t data, bool logit)
490 {
491 	/* writes to register $CC need to force a partial update */
492 	if ((offset & ~1) == 0xcc)
493 		m_screen->update_partial(m_screen->vpos());
494 
495 	/* write to high part on odd addresses */
496 	if (offset & 1)
497 		m_zeusbase[offset & ~1] = (m_zeusbase[offset & ~1] & 0x0000ffff) | (data << 16);
498 
499 	/* write to low part on event addresses */
500 	else
501 		m_zeusbase[offset & ~1] = (m_zeusbase[offset & ~1] & 0xffff0000) | (data & 0xffff);
502 
503 	/* log appropriately */
504 	if (logit)
505 		logerror("(%02X) = %04X [%08X]\n", offset, data & 0xffff, m_zeusbase[offset & ~1]);
506 
507 	/* handle the update */
508 	if ((offset & 1) == 0)
509 		zeus_register_update(offset);
510 }
511 
512 
zeus_register32_w(offs_t offset,uint32_t data,bool logit)513 void midzeus_state::zeus_register32_w(offs_t offset, uint32_t data, bool logit)
514 {
515 	/* writes to register $CC need to force a partial update */
516 	if ((offset & ~1) == 0xcc)
517 		m_screen->update_partial(m_screen->vpos());
518 
519 	/* always write to low word? */
520 	m_zeusbase[offset & ~1] = data;
521 
522 	/* log appropriately */
523 	if (logit)
524 	{
525 		if (offset & 1)
526 			logerror("(%02X) = %08X -- unexpected in 32-bit mode\n", offset, data);
527 		else if (offset != 0xe0)
528 			logerror("(%02X) = %08X\n", offset, data);
529 		else
530 			logerror("(%02X) = %08X\n", offset, data);
531 	}
532 
533 	/* handle the update */
534 	if ((offset & 1) == 0)
535 		zeus_register_update(offset);
536 }
537 
538 
539 
540 /*************************************
541  *
542  *  Update state after a register write
543  *
544  *************************************/
545 
zeus_register_update(offs_t offset)546 void midzeus_state::zeus_register_update(offs_t offset)
547 {
548 	/* handle the writes; only trigger on low accesses */
549 	switch (offset)
550 	{
551 		case 0x52:
552 			m_zeusbase[0xb2] = m_zeusbase[0x52];
553 			break;
554 
555 		case 0x60:
556 			/* invasn writes here to execute a command (?) */
557 			if (m_zeusbase[0x60] & 1)
558 			{
559 				if ((m_zeusbase[0x80] & 0xffffff) == 0x22FCFF)
560 				{
561 					// m_zeusbase[0x00] = color
562 					// m_zeusbase[0x02] = ??? = 0x000C0000
563 					// m_zeusbase[0x04] = ??? = 0x00000E01
564 					// m_zeusbase[0x06] = ??? = 0xFFFF0030
565 					// m_zeusbase[0x08] = vert[0] = (y0 << 16) | x0
566 					// m_zeusbase[0x0a] = vert[1] = (y1 << 16) | x1
567 					// m_zeusbase[0x0c] = vert[2] = (y2 << 16) | x2
568 					// m_zeusbase[0x0e] = vert[3] = (y3 << 16) | x3
569 					// m_zeusbase[0x18] = ??? = 0xFFFFFFFF
570 					// m_zeusbase[0x1a] = ??? = 0xFFFFFFFF
571 					// m_zeusbase[0x1c] = ??? = 0xFFFFFFFF
572 					// m_zeusbase[0x1e] = ??? = 0xFFFFFFFF
573 					// m_zeusbase[0x20] = ??? = 0x00000000
574 					// m_zeusbase[0x22] = ??? = 0x00000000
575 					// m_zeusbase[0x24] = ??? = 0x00000000
576 					// m_zeusbase[0x26] = ??? = 0x00000000
577 					// m_zeusbase[0x40] = ??? = 0x00000000
578 					// m_zeusbase[0x42] = ??? = 0x00000000
579 					// m_zeusbase[0x44] = ??? = 0x00000000
580 					// m_zeusbase[0x46] = ??? = 0x00000000
581 					// m_zeusbase[0x4c] = ??? = 0x00808080 (brightness?)
582 					// m_zeusbase[0x4e] = ??? = 0x00808080 (brightness?)
583 					mz_poly_extra_data& extra = m_poly->object_data_alloc();
584 					poly_vertex vert[4];
585 
586 					vert[0].x = (int16_t)m_zeusbase[0x08];
587 					vert[0].y = (int16_t)(m_zeusbase[0x08] >> 16);
588 					vert[1].x = (int16_t)m_zeusbase[0x0a];
589 					vert[1].y = (int16_t)(m_zeusbase[0x0a] >> 16);
590 					vert[2].x = (int16_t)m_zeusbase[0x0c];
591 					vert[2].y = (int16_t)(m_zeusbase[0x0c] >> 16);
592 					vert[3].x = (int16_t)m_zeusbase[0x0e];
593 					vert[3].y = (int16_t)(m_zeusbase[0x0e] >> 16);
594 
595 					extra.solidcolor = m_zeusbase[0x00];
596 					extra.zoffset = 0x7fff;
597 
598 					m_poly->zeus_draw_debug_quad(m_zeus_cliprect, vert);
599 					m_poly->wait("Normal");
600 				}
601 				else
602 					logerror("Execute unknown command\n");
603 			}
604 			break;
605 
606 		case 0x70:
607 			m_zeus_point[0] = m_zeusbase[0x70] << 16;
608 			break;
609 
610 		case 0x72:
611 			m_zeus_point[1] = m_zeusbase[0x72] << 16;
612 			break;
613 
614 		case 0x74:
615 			m_zeus_point[2] = m_zeusbase[0x74] << 16;
616 			break;
617 
618 		case 0x80:
619 			/* this bit enables the "FIFO empty" IRQ; since our virtual FIFO is always empty,
620 			    we simply assert immediately if this is enabled. invasn needs this for proper
621 			    operations */
622 			if (m_zeusbase[0x80] & 0x02000000)
623 				m_maincpu->set_input_line(2, ASSERT_LINE);
624 			else
625 				m_maincpu->set_input_line(2, CLEAR_LINE);
626 			break;
627 
628 		case 0x84:
629 			/* MK4: Written in tandem with 0xcc */
630 			/* MK4: Writes either 0x80 (and 0x000000 to 0xcc) or 0x00 (and 0x800000 to 0xcc) */
631 			m_zeus_renderbase = waveram1_ptr_from_expanded_addr(m_zeusbase[0x84] << 16);
632 			break;
633 
634 		case 0xb0:
635 		case 0xb2:
636 			if ((m_zeusbase[0xb6] >> 16) != 0)
637 			{
638 				if ((offset == 0xb0 && (m_zeusbase[0xb6] & 0x02000000) == 0) ||
639 					(offset == 0xb2 && (m_zeusbase[0xb6] & 0x02000000) != 0))
640 				{
641 					void *dest;
642 
643 					if (m_zeusbase[0xb6] & 0x80000000)
644 						dest = waveram1_ptr_from_expanded_addr(m_zeusbase[0xb4]);
645 					else
646 						dest = waveram0_ptr_from_expanded_addr(m_zeusbase[0xb4]);
647 
648 					if (m_zeusbase[0xb6] & 0x00100000)
649 						WAVERAM_WRITE16(dest, 0, m_zeusbase[0xb0]);
650 					if (m_zeusbase[0xb6] & 0x00200000)
651 						WAVERAM_WRITE16(dest, 1, m_zeusbase[0xb0] >> 16);
652 					if (m_zeusbase[0xb6] & 0x00400000)
653 						WAVERAM_WRITE16(dest, 2, m_zeusbase[0xb2]);
654 					if (m_zeusbase[0xb6] & 0x00800000)
655 						WAVERAM_WRITE16(dest, 3, m_zeusbase[0xb2] >> 16);
656 					if (m_zeusbase[0xb6] & 0x00020000)
657 						m_zeusbase[0xb4]++;
658 				}
659 			}
660 			break;
661 
662 		case 0xb4:
663 			if (m_zeusbase[0xb6] & 0x00010000)
664 			{
665 				const uint32_t *src;
666 
667 				if (m_zeusbase[0xb6] & 0x80000000)
668 					src = (const uint32_t *)waveram1_ptr_from_expanded_addr(m_zeusbase[0xb4]);
669 				else
670 					src = (const uint32_t *)waveram0_ptr_from_expanded_addr(m_zeusbase[0xb4]);
671 
672 				m_poly->wait("vram_read");
673 				m_zeusbase[0xb0] = WAVERAM_READ32(src, 0);
674 				m_zeusbase[0xb2] = WAVERAM_READ32(src, 1);
675 			}
676 			break;
677 
678 		case 0xc0:
679 		case 0xc2:
680 		case 0xc4:
681 		case 0xc6:
682 		case 0xc8:
683 		case 0xca:
684 			m_screen->update_partial(m_screen->vpos());
685 			{
686 				int vtotal = m_zeusbase[0xca] >> 16;
687 				int htotal = m_zeusbase[0xc6] >> 16;
688 
689 				rectangle visarea(m_zeusbase[0xc6] & 0xffff, htotal - 3, 0, m_zeusbase[0xc8] & 0xffff);
690 				if (htotal > 0 && vtotal > 0 && visarea.min_x < visarea.max_x && visarea.max_y < vtotal)
691 				{
692 					m_screen->configure(htotal, vtotal, visarea, HZ_TO_ATTOSECONDS(MIDZEUS_VIDEO_CLOCK / 8.0 / (htotal * vtotal)));
693 					m_zeus_cliprect = visarea;
694 					m_zeus_cliprect.max_x -= m_zeus_cliprect.min_x;
695 					m_zeus_cliprect.min_x = 0;
696 				}
697 			}
698 			break;
699 
700 		case 0xcc:
701 			m_screen->update_partial(m_screen->vpos());
702 			m_log_fifo = machine().input().code_pressed(KEYCODE_L);
703 			break;
704 
705 		case 0xe0:
706 			m_zeus_fifo[m_zeus_fifo_words++] = m_zeusbase[0xe0];
707 			if (zeus_fifo_process(m_zeus_fifo, m_zeus_fifo_words))
708 				m_zeus_fifo_words = 0;
709 			break;
710 	}
711 }
712 
713 
714 
715 /*************************************
716  *
717  *  Process the FIFO
718  *
719  *************************************/
720 
zeus_fifo_process(const uint32_t * data,int numwords)721 int midzeus_state::zeus_fifo_process(const uint32_t *data, int numwords)
722 {
723 	/* handle logging */
724 	switch (data[0] >> 24)
725 	{
726 		/* 0x00/0x01: set pointer */
727 		/* in model data, this is 0x0C */
728 		case 0x00:
729 		case 0x01:
730 			if (numwords < 2 && data[0] != 0)
731 				return false;
732 			if (m_log_fifo)
733 				log_fifo_command(data, numwords, "");
734 			zeus_pointer_w(data[0] & 0xffffff, data[1], m_log_fifo);
735 			break;
736 
737 		/* 0x13: render model based on previously set information */
738 		case 0x13:  /* invasn */
739 			if (m_log_fifo)
740 				log_fifo_command(data, numwords, "");
741 			zeus_draw_model((m_zeusbase[0x06] << 16), m_log_fifo);
742 			break;
743 
744 		/* 0x17: write 16-bit value to low registers */
745 		case 0x17:
746 			if (m_log_fifo)
747 				log_fifo_command(data, numwords, " -- reg16");
748 			zeus_register16_w((data[0] >> 16) & 0x7f, data[0], m_log_fifo);
749 			break;
750 
751 		/* 0x18: write 32-bit value to low registers */
752 		/* in model data, this is 0x19 */
753 		case 0x18:
754 			if (numwords < 2)
755 				return false;
756 			if (m_log_fifo)
757 				log_fifo_command(data, numwords, " -- reg32");
758 			zeus_register32_w((data[0] >> 16) & 0x7f, data[1], m_log_fifo);
759 			break;
760 
761 		/* 0x1A/0x1B: sync pipeline(?) */
762 		case 0x1a:
763 		case 0x1b:
764 			if (m_log_fifo)
765 				log_fifo_command(data, numwords, " -- sync\n");
766 			break;
767 
768 		/* 0x1C/0x1E: write matrix and translation vector */
769 		case 0x1c:
770 		case 0x1e:
771 
772 			/* single matrix form */
773 			if ((data[0] & 0xffff) != 0x7fff)
774 			{
775 				/* requires 8 words total */
776 				if (numwords < 8)
777 					return false;
778 				if (m_log_fifo)
779 				{
780 					log_fifo_command(data, numwords, "");
781 					logerror("\n\t\tmatrix ( %04X %04X %04X ) ( %04X %04X %04X ) ( %04X %04X %04X )\n\t\tvector %8.2f %8.2f %8.5f\n",
782 						data[2] & 0xffff,   data[2] >> 16,      data[0] & 0xffff,
783 						data[3] & 0xffff,   data[3] >> 16,      data[1] >> 16,
784 						data[4] & 0xffff,   data[4] >> 16,      data[1] & 0xffff,
785 						(double)(int32_t)data[5] * (1.0 / 65536.0),
786 						(double)(int32_t)data[6] * (1.0 / 65536.0),
787 						(double)(int32_t)data[7] * (1.0 / (65536.0 * 512.0)));
788 				}
789 
790 				/* extract the matrix from the raw data */
791 				m_zeus_matrix[0][0] = data[2];    m_zeus_matrix[0][1] = data[2] >> 16;  m_zeus_matrix[0][2] = data[0];
792 				m_zeus_matrix[1][0] = data[3];    m_zeus_matrix[1][1] = data[3] >> 16;  m_zeus_matrix[1][2] = data[1] >> 16;
793 				m_zeus_matrix[2][0] = data[4];    m_zeus_matrix[2][1] = data[4] >> 16;  m_zeus_matrix[2][2] = data[1];
794 
795 				/* extract the translation point from the raw data */
796 				m_zeus_point[0] = data[5];
797 				m_zeus_point[1] = data[6];
798 				m_zeus_point[2] = data[7];
799 			}
800 
801 			/* double matrix form */
802 			else
803 			{
804 				int16_t matrix1[3][3];
805 				int16_t matrix2[3][3];
806 
807 				/* requires 13 words total */
808 				if (numwords < 13)
809 					return false;
810 				if (m_log_fifo)
811 				{
812 					log_fifo_command(data, numwords, "");
813 					logerror("\n\t\tmatrix ( %04X %04X %04X ) ( %04X %04X %04X ) ( %04X %04X %04X )\n\t\tmatrix ( %04X %04X %04X ) ( %04X %04X %04X ) ( %04X %04X %04X )\n\t\tvector %8.2f %8.2f %8.5f\n",
814 						data[4] & 0xffff,   data[4] >> 16,      data[5] >> 16,
815 						data[8] & 0xffff,   data[8] >> 16,      data[6] >> 16,
816 						data[9] & 0xffff,   data[9] >> 16,      data[7] >> 16,
817 						data[1] & 0xffff,   data[2] & 0xffff,   data[3] & 0xffff,
818 						data[1] >> 16,      data[2] >> 16,      data[3] >> 16,
819 						data[5] & 0xffff,   data[6] & 0xffff,   data[7] & 0xffff,
820 						(double)(int32_t)data[10] * (1.0 / 65536.0),
821 						(double)(int32_t)data[11] * (1.0 / 65536.0),
822 						(double)(int32_t)data[12] * (1.0 / (65536.0 * 512.0)));
823 				}
824 
825 				/* extract the first matrix from the raw data */
826 				matrix1[0][0] = data[4];        matrix1[0][1] = data[4] >> 16;  matrix1[0][2] = data[5] >> 16;
827 				matrix1[1][0] = data[8];        matrix1[1][1] = data[8] >> 16;  matrix1[1][2] = data[6] >> 16;
828 				matrix1[2][0] = data[9];        matrix1[2][1] = data[9] >> 16;  matrix1[2][2] = data[7] >> 16;
829 
830 				/* extract the second matrix from the raw data */
831 				matrix2[0][0] = data[1];        matrix2[0][1] = data[2];        matrix2[0][2] = data[3];
832 				matrix2[1][0] = data[1] >> 16;  matrix2[1][1] = data[2] >> 16;  matrix2[1][2] = data[3] >> 16;
833 				matrix2[2][0] = data[5];        matrix2[2][1] = data[6];        matrix2[2][2] = data[7];
834 
835 				/* multiply them together to get the final matrix */
836 				m_zeus_matrix[0][0] = ((int64_t)(matrix1[0][0] * matrix2[0][0]) + (int64_t)(matrix1[0][1] * matrix2[1][0]) + (int64_t)(matrix1[0][2] * matrix2[2][0])) >> 16;
837 				m_zeus_matrix[0][1] = ((int64_t)(matrix1[0][0] * matrix2[0][1]) + (int64_t)(matrix1[0][1] * matrix2[1][1]) + (int64_t)(matrix1[0][2] * matrix2[2][1])) >> 16;
838 				m_zeus_matrix[0][2] = ((int64_t)(matrix1[0][0] * matrix2[0][2]) + (int64_t)(matrix1[0][1] * matrix2[1][2]) + (int64_t)(matrix1[0][2] * matrix2[2][2])) >> 16;
839 				m_zeus_matrix[1][0] = ((int64_t)(matrix1[1][0] * matrix2[0][0]) + (int64_t)(matrix1[1][1] * matrix2[1][0]) + (int64_t)(matrix1[1][2] * matrix2[2][0])) >> 16;
840 				m_zeus_matrix[1][1] = ((int64_t)(matrix1[1][0] * matrix2[0][1]) + (int64_t)(matrix1[1][1] * matrix2[1][1]) + (int64_t)(matrix1[1][2] * matrix2[2][1])) >> 16;
841 				m_zeus_matrix[1][2] = ((int64_t)(matrix1[1][0] * matrix2[0][2]) + (int64_t)(matrix1[1][1] * matrix2[1][2]) + (int64_t)(matrix1[1][2] * matrix2[2][2])) >> 16;
842 				m_zeus_matrix[2][0] = ((int64_t)(matrix1[2][0] * matrix2[0][0]) + (int64_t)(matrix1[2][1] * matrix2[1][0]) + (int64_t)(matrix1[2][2] * matrix2[2][0])) >> 16;
843 				m_zeus_matrix[2][1] = ((int64_t)(matrix1[2][0] * matrix2[0][1]) + (int64_t)(matrix1[2][1] * matrix2[1][1]) + (int64_t)(matrix1[2][2] * matrix2[2][1])) >> 16;
844 				m_zeus_matrix[2][2] = ((int64_t)(matrix1[2][0] * matrix2[0][2]) + (int64_t)(matrix1[2][1] * matrix2[1][2]) + (int64_t)(matrix1[2][2] * matrix2[2][2])) >> 16;
845 
846 				/* extract the translation point from the raw data */
847 				m_zeus_point[0] = data[10];
848 				m_zeus_point[1] = data[11];
849 				m_zeus_point[2] = data[12];
850 			}
851 			break;
852 
853 		/* 0x23: some additional X,Y,Z coordinates */
854 		/* 0x2e: same for invasn */
855 		case 0x23:
856 		case 0x2e:
857 			if (numwords < 2)
858 				return false;
859 			if (m_log_fifo)
860 			{
861 				log_fifo_command(data, numwords, "");
862 				logerror(" -- light xyz = %d,%d,%d\n", (int16_t)data[1], (int16_t)(data[1] >> 16), (int16_t)data[0]);
863 			}
864 
865 			m_zeus_light[0] = (int16_t)(data[1] & 0xffff);
866 			m_zeus_light[1] = (int16_t)(data[1] >> 16);
867 			m_zeus_light[2] = (int16_t)(data[0] & 0xffff);
868 			break;
869 		/* 0x25: display control? */
870 		/* 0x28: same for mk4b */
871 		/* 0x30: same for invasn */
872 		case 0x25:
873 		{
874 			/* 0x25 is used differently in mk4b. What determines this? */
875 			if (m_is_mk4b)
876 			{
877 				if (numwords < 2)
878 					return false;
879 
880 				break;
881 			}
882 		}
883 		case 0x28:
884 		case 0x30:
885 			if (numwords < 4 || ((data[0] & 0x808000) && numwords < 10))
886 				return false;
887 
888 			if (m_log_fifo)
889 				log_fifo_command(data, numwords, " -- alt. quad and hack screen clear\n");
890 
891 			if ((numwords < 10) && (data[0] & 0xffff7f) == 0)
892 			{
893 				/* not right -- just a hack */
894 				int x, y;
895 				for (y = m_zeus_cliprect.min_y; y <= m_zeus_cliprect.max_y; y++)
896 					for (x = m_zeus_cliprect.min_x; x <= m_zeus_cliprect.max_x; x++)
897 						waveram_plot_depth(y, x, 0, 0x7fff);
898 			}
899 			else
900 			{
901 				uint32_t texdata = (m_zeusbase[0x06] << 16) | (m_zeusbase[0x00] >> 16);
902 				m_poly->zeus_draw_quad(false, data, texdata, m_log_fifo);
903 			}
904 			break;
905 
906 		/* 0x2d: unknown - invasn */
907 		/* 0x70: same for mk4 */
908 		case 0x2d:
909 		case 0x70:
910 			if (m_log_fifo)
911 				log_fifo_command(data, numwords, "\n");
912 			break;
913 
914 		/* 0x67: render model with inline texture info */
915 		case 0x67:
916 			if (numwords < 3)
917 				return false;
918 			if (m_log_fifo)
919 				log_fifo_command(data, numwords, "");
920 			m_zeus_objdata = data[1];
921 			zeus_draw_model(data[2], m_log_fifo);
922 			break;
923 
924 		default:
925 			printf("Unknown command %08X\n", data[0]);
926 			if (m_log_fifo)
927 				log_fifo_command(data, numwords, "\n");
928 			break;
929 	}
930 	return true;
931 }
932 
933 
934 
935 /*************************************
936  *
937  *  Draw a model in waveram
938  *
939  *************************************/
940 
zeus_draw_model(uint32_t texdata,bool logit)941 void midzeus_state::zeus_draw_model(uint32_t texdata, bool logit)
942 {
943 	uint32_t databuffer[32];
944 	int databufcount = 0;
945 	int model_done = false;
946 
947 	if (logit)
948 		logerror(" -- model @ %08X\n", m_zeus_objdata);
949 
950 	while (m_zeus_objdata != 0 && !model_done)
951 	{
952 		const void *base = waveram0_ptr_from_block_addr(m_zeus_objdata);
953 		int count = m_zeus_objdata >> 24;
954 		int curoffs;
955 
956 		/* reset the objdata address */
957 		m_zeus_objdata = 0;
958 
959 		/* loop until we run out of data */
960 		for (curoffs = 0; curoffs <= count; curoffs++)
961 		{
962 			int countneeded;
963 			uint8_t cmd;
964 
965 			/* accumulate 2 words of data */
966 			databuffer[databufcount++] = WAVERAM_READ32(base, curoffs * 2 + 0);
967 			databuffer[databufcount++] = WAVERAM_READ32(base, curoffs * 2 + 1);
968 
969 			/* if this is enough, process the command */
970 			cmd = databuffer[0] >> 24;
971 			countneeded = (cmd == 0x25 || cmd == 0x30 || cmd == 0x28) ? 14 : 2;
972 			if (databufcount == countneeded)
973 			{
974 				/* handle logging of the command */
975 				if (logit)
976 				{
977 					int offs;
978 					logerror("\t");
979 					for (offs = 0; offs < databufcount; offs++)
980 						logerror("%08X ", databuffer[offs]);
981 					logerror("-- ");
982 				}
983 
984 				/* handle the command */
985 				switch (cmd)
986 				{
987 					case 0x08:
988 						if (logit)
989 							logerror("end of model\n");
990 						model_done = true;
991 						break;
992 
993 					case 0x0c:  /* mk4/invasn */
994 						zeus_pointer_w(databuffer[0] & 0xffffff, databuffer[1], logit);
995 						break;
996 
997 					case 0x17:  /* mk4 */
998 						if (logit)
999 							logerror("reg16");
1000 						zeus_register16_w((databuffer[0] >> 16) & 0x7f, databuffer[0], logit);
1001 						if (((databuffer[0] >> 16) & 0x7f) == 0x06)
1002 							texdata = (texdata & 0xffff) | (m_zeusbase[0x06] << 16);
1003 						break;
1004 
1005 					case 0x19:  /* invasn */
1006 						if (logit)
1007 							logerror("reg32");
1008 						zeus_register32_w((databuffer[0] >> 16) & 0x7f, databuffer[1], logit);
1009 						if (((databuffer[0] >> 16) & 0x7f) == 0x06)
1010 							texdata = (texdata & 0xffff) | (m_zeusbase[0x06] << 16);
1011 						break;
1012 
1013 					case 0x25:  /* mk4 */
1014 					case 0x28:  /* mk4r1 */
1015 					case 0x30:  /* invasn */
1016 						m_poly->zeus_draw_quad(true, databuffer, texdata, logit);
1017 						break;
1018 
1019 					default:
1020 						if (logit)
1021 							logerror("unknown\n");
1022 						break;
1023 				}
1024 
1025 				/* reset the count */
1026 				databufcount = 0;
1027 			}
1028 		}
1029 	}
1030 }
1031 
1032 
1033 
1034 /*************************************
1035  *
1036  *  Draw a quad
1037  *
1038  *************************************/
1039 
zeus_draw_quad(int long_fmt,const uint32_t * databuffer,uint32_t texdata,bool logit)1040 void midzeus_renderer::zeus_draw_quad(int long_fmt, const uint32_t *databuffer, uint32_t texdata, bool logit)
1041 {
1042 	poly_vertex clipvert[8];
1043 	poly_vertex vert[4];
1044 	uint32_t ushift, vshift;
1045 	float maxy, maxx;
1046 	uint32_t texbase, texwshift;
1047 	uint32_t numverts;
1048 
1049 	uint32_t ctrl_word = databuffer[long_fmt ? 1 : 9];
1050 
1051 	texbase = ((texdata >> 10) & 0x3f0000) | (texdata & 0xffff);
1052 	texwshift = (texdata >> 22) & 7;
1053 
1054 	ushift = 8 - ((m_state.m_zeusbase[0x04] >> 4) & 3);
1055 	vshift = 8 - ((m_state.m_zeusbase[0x04] >> 6) & 3);
1056 
1057 	int xy_offset = long_fmt ? 2 : 1;
1058 
1059 	int16_t (*zeus_matrix)[3] = m_state.m_zeus_matrix;
1060 	int32_t *zeus_point = m_state.m_zeus_point;
1061 
1062 	for (uint32_t i = 0; i < 4; i++)
1063 	{
1064 		uint32_t ixy = databuffer[xy_offset + i*2];
1065 		uint32_t iuvz = databuffer[xy_offset + 1 + i*2];
1066 		int32_t xo = (int16_t)ixy;
1067 		int32_t yo = (int16_t)(ixy >> 16);
1068 		int32_t zo = (int16_t)iuvz;
1069 		uint8_t u = iuvz >> 16;
1070 		uint8_t v = iuvz >> 24;
1071 		int64_t x, y, z;
1072 
1073 		x = (int64_t)(xo * zeus_matrix[0][0]) + (int64_t)(yo * zeus_matrix[0][1]) + (int64_t)(zo * zeus_matrix[0][2]) + zeus_point[0];
1074 		y = (int64_t)(xo * zeus_matrix[1][0]) + (int64_t)(yo * zeus_matrix[1][1]) + (int64_t)(zo * zeus_matrix[1][2]) + zeus_point[1];
1075 		z = (int64_t)(xo * zeus_matrix[2][0]) + (int64_t)(yo * zeus_matrix[2][1]) + (int64_t)(zo * zeus_matrix[2][2]) + zeus_point[2];
1076 
1077 		// Rounding hack
1078 		x = (x + 0x00004000) & ~0x00007fffULL;
1079 		y = (y + 0x00004000) & ~0x00007fffULL;
1080 		z = (z + 0x00004000) & ~0x00007fffULL;
1081 
1082 		// back face cull using polygon normal and first vertex
1083 		if (i == 0)
1084 		{
1085 			int16_t normal[3];
1086 			int32_t rotnormal[3];
1087 
1088 			normal[0] = (int8_t)(databuffer[0] >> 0);
1089 			normal[1] = (int8_t)(databuffer[0] >> 8);
1090 			normal[2] = (int8_t)(databuffer[0] >> 16);
1091 
1092 			rotnormal[0] = normal[0] * zeus_matrix[0][0] + normal[1] * zeus_matrix[0][1] + normal[2] * zeus_matrix[0][2];
1093 			rotnormal[1] = normal[0] * zeus_matrix[1][0] + normal[1] * zeus_matrix[1][1] + normal[2] * zeus_matrix[1][2];
1094 			rotnormal[2] = normal[0] * zeus_matrix[2][0] + normal[1] * zeus_matrix[2][1] + normal[2] * zeus_matrix[2][2];
1095 
1096 			int64_t dot = rotnormal[0] * x + rotnormal[1] * y + rotnormal[2] * z;
1097 
1098 			if (dot >= 0)
1099 				return;
1100 		}
1101 
1102 		if (long_fmt)
1103 		{
1104 #if 0
1105 			// TODO: Lighting
1106 			uint32_t inormal = databuffer[10 + i];
1107 			int32_t xn = (int32_t)(((inormal >>  0) & 0x3ff) << 22) >> 22;
1108 			int32_t yn = (int32_t)(((inormal >> 10) & 0x3ff) << 22) >> 22;
1109 			int32_t zn = (int32_t)(((inormal >> 20) & 0x3ff) << 22) >> 22;
1110 #endif
1111 		}
1112 
1113 		vert[i].x = x;
1114 		vert[i].y = y;
1115 		vert[i].p[0] = z;
1116 		vert[i].p[1] = u << ushift;
1117 		vert[i].p[2] = v << vshift;
1118 		vert[i].p[3] = 0xffff;
1119 
1120 		if (logit)
1121 		{
1122 			m_state.logerror("\t\t(%f,%f,%f) UV:(%02X,%02X) UV_SCALE:(%02X,%02X) (%03X,%03X,%03X) dot=%08X\n",
1123 					(double) vert[i].x * (1.0 / 65536.0), (double) vert[i].y * (1.0 / 65536.0), (double) vert[i].p[0] * (1.0 / 65536.0),
1124 					(iuvz >> 16) & 0xff, (iuvz >> 24) & 0xff,
1125 					(int)(vert[i].p[1] / 256.0f), (int)(vert[i].p[2] / 256.0f),
1126 					(databuffer[10 + i] >> 20) & 0x3ff, (databuffer[10 + i] >> 10) & 0x3ff, (databuffer[10 + i] >> 0) & 0x3ff,
1127 					0);
1128 		}
1129 	}
1130 
1131 	numverts = m_state.m_poly->zclip_if_less(4, &vert[0], &clipvert[0], 4, 512.0f);
1132 	if (numverts < 3)
1133 		return;
1134 
1135 	maxx = maxy = -1000.0f;
1136 	for (uint32_t i = 0; i < numverts; i++)
1137 	{
1138 		float ooz = 512.0f / clipvert[i].p[0];
1139 
1140 		clipvert[i].x *= ooz;
1141 		clipvert[i].y *= ooz;
1142 		clipvert[i].x += 200.5f;
1143 		clipvert[i].y += 128.5f;
1144 
1145 		maxx = std::max(maxx, clipvert[i].x);
1146 		maxy = std::max(maxy, clipvert[i].y);
1147 
1148 		if (logit)
1149 			m_state.logerror("\t\t\tTranslated=(%f,%f,%f)\n", (double) clipvert[i].x, (double) clipvert[i].y, (double) clipvert[i].p[0]);
1150 	}
1151 	for (uint32_t i = 0; i < numverts; i++)
1152 	{
1153 		if (clipvert[i].x == maxx)
1154 			clipvert[i].x += 0.0005f;
1155 		if (clipvert[i].y == maxy)
1156 			clipvert[i].y += 0.0005f;
1157 	}
1158 
1159 	mz_poly_extra_data& extra = m_state.m_poly->object_data_alloc();
1160 
1161 	if (ctrl_word & 0x01000000)
1162 	{
1163 		uint32_t tex_type = (texdata >> 16) & 3;
1164 		extra.texwidth = 512 >> texwshift;
1165 		extra.voffset = ctrl_word & 0xffff;
1166 
1167 		extra.texbase = m_state.waveram0_ptr_from_texture_addr(texbase, extra.texwidth);
1168 
1169 		if (tex_type == 1)
1170 		{
1171 			extra.get_texel = texdata & 0x00200000 ? get_texel_8bit : get_texel_4bit;
1172 		}
1173 		else if (tex_type == 2)
1174 		{
1175 			extra.get_texel = texdata & 0x00200000 ? get_texel_alt_8bit : get_texel_alt_4bit;
1176 		}
1177 		else
1178 		{
1179 			printf("Unknown texture type: %d\n", tex_type);
1180 			return;
1181 		}
1182 	}
1183 
1184 	extra.ctrl_word = ctrl_word;
1185 	extra.solidcolor = m_state.m_zeusbase[0x00] & 0x7fff;
1186 	extra.zoffset = m_state.m_zeusbase[0x7e] >> 16;
1187 	extra.alpha = m_state.m_zeusbase[0x4e];
1188 	extra.blend = m_state.m_zeusbase[0x5c];
1189 	extra.depth_test_enable = !(m_state.m_zeusbase[0x04] & 0x800);
1190 	extra.depth_write_enable = m_state.m_zeusbase[0x04] & 0x200;
1191 	extra.transcolor = ((ctrl_word >> 16) & 1) ? 0 : 0x100;
1192 	extra.palbase = m_state.waveram0_ptr_from_block_addr(m_state.m_zeus_palbase);
1193 
1194 	// Note: Before being upgraded to the new polygon rasterizing code, this function call was
1195 	//       a poly_render_quad_fan.  It appears as though the new code defaults to a fan if
1196 	//       the template argument is 4, but keep an eye out for missing quads.
1197 	m_state.m_poly->render_polygon<4>(m_state.m_zeus_cliprect,
1198 							render_delegate(&midzeus_renderer::render_poly, this),
1199 							4,
1200 							clipvert);
1201 }
1202 
zeus_draw_debug_quad(const rectangle & rect,const vertex_t * vert)1203 void midzeus_renderer::zeus_draw_debug_quad(const rectangle& rect, const vertex_t *vert)
1204 {
1205 	m_state.m_poly->render_polygon<4>(rect, render_delegate(&midzeus_renderer::render_poly_solid_fixedz, this), 0, vert);
1206 }
1207 
1208 
1209 /*************************************
1210  *
1211  *  Rasterizers
1212  *
1213  *************************************/
1214 
render_poly(int32_t scanline,const extent_t & extent,const mz_poly_extra_data & object,int threadid)1215 void midzeus_renderer::render_poly(int32_t scanline, const extent_t& extent, const mz_poly_extra_data& object, int threadid)
1216 {
1217 	int32_t curz = extent.param[0].start;
1218 	int32_t curu = extent.param[1].start;
1219 	int32_t curv = extent.param[2].start;
1220 	int32_t curi = extent.param[3].start;
1221 	int32_t dzdx = extent.param[0].dpdx;
1222 	int32_t dudx = extent.param[1].dpdx;
1223 	int32_t dvdx = extent.param[2].dpdx;
1224 	int32_t didx = extent.param[3].dpdx;
1225 	const void *texbase = object.texbase;
1226 	const void *palbase = object.palbase;
1227 	uint16_t transcolor = object.transcolor;
1228 	uint32_t texwidth = object.texwidth;
1229 
1230 	for (uint32_t x = extent.startx; x < extent.stopx; x++)
1231 	{
1232 		uint16_t *depthptr = WAVERAM_PTRDEPTH(m_state.m_zeus_renderbase, scanline, x);
1233 		int32_t depth = (curz >> 16) + object.zoffset;
1234 
1235 		if (depth > 0x7fff)
1236 			depth = 0x7fff;
1237 
1238 		uint32_t i8 = curi >> 8;
1239 
1240 		bool depth_pass;
1241 
1242 		if (object.depth_test_enable)
1243 			depth_pass = depth >= 0 && depth <= *depthptr;
1244 		else
1245 			depth_pass = true;
1246 
1247 		if (depth_pass)
1248 		{
1249 			rgb_t src=0;
1250 
1251 			bool src_valid = true;
1252 
1253 			if ((object.ctrl_word & 0x000c0000) == 0x000c0000)
1254 			{
1255 				src.set_r(pal5bit(object.solidcolor >> 10));
1256 				src.set_g(pal5bit(object.solidcolor >> 5));
1257 				src.set_b(pal5bit(object.solidcolor));
1258 			}
1259 			else
1260 			{
1261 				uint32_t u0 = curu >> 8;
1262 				uint32_t v0 = object.voffset + (curv >> 8);
1263 				uint32_t u1 = u0 + 1;
1264 				uint32_t v1 = v0 + 1;
1265 
1266 				uint8_t texels[4];
1267 
1268 				texels[0] = object.get_texel(texbase, v0, u0, texwidth);
1269 				texels[1] = object.get_texel(texbase, v0, u1, texwidth);
1270 				texels[2] = object.get_texel(texbase, v1, u0, texwidth);
1271 				texels[3] = object.get_texel(texbase, v1, u1, texwidth);
1272 
1273 				if (texels[0] != transcolor)
1274 				{
1275 					rgb_t color[4] = {0, 0, 0, 0};
1276 
1277 					for (uint32_t i = 0; i < 4; ++i)
1278 					{
1279 						uint16_t pix = WAVERAM_READ16(palbase, texels[i]);
1280 
1281 						color[i].set_r(pal5bit(pix >> 10));
1282 						color[i].set_g(pal5bit(pix >> 5));
1283 						color[i].set_b(pal5bit(pix));
1284 					}
1285 
1286 					src = rgbaint_t::bilinear_filter(color[0], color[1], color[2], color[3], curu & 0xff, curv & 0xff);
1287 				}
1288 				else
1289 				{
1290 					src_valid = false;
1291 				}
1292 			}
1293 
1294 			if (src_valid)
1295 			{
1296 				uint32_t srcr = src.r();
1297 				uint32_t srcg = src.g();
1298 				uint32_t srcb = src.b();
1299 
1300 				uint32_t dstr = 0;
1301 				uint32_t dstg = 0;
1302 				uint32_t dstb = 0;
1303 
1304 				uint32_t outr = 0;
1305 				uint32_t outg = 0;
1306 				uint32_t outb = 0;
1307 
1308 				uint32_t srca = object.alpha & 0xff;
1309 				uint32_t dsta = (object.alpha >> 8) & 0xff;
1310 
1311 				// Destination enable?
1312 				if (object.blend & 0x00800000)
1313 				{
1314 					uint16_t dst = WAVERAM_READPIX(m_state.m_zeus_renderbase, scanline, x);
1315 
1316 					dstr = (dst >> 10) & 0x1f;
1317 					dstg = (dst >> 5) & 0x1f;
1318 					dstb = dst & 0x1f;
1319 
1320 					dstr = (dstr << 3) | (dstr >> 2);
1321 					dstg = (dstg << 3) | (dstg >> 2);
1322 					dstb = (dstb << 3) | (dstb >> 2);
1323 				}
1324 
1325 				switch (object.blend)
1326 				{
1327 					case BLEND_OPAQUE1:
1328 					{
1329 						outr = srcr;
1330 						outg = srcg;
1331 						outb = srcb;
1332 						break;
1333 					}
1334 
1335 					case BLEND_OPAQUE2:
1336 					{
1337 						outr = (srcr * i8) >> 8;
1338 						outg = (srcg * i8) >> 8;
1339 						outb = (srcb * i8) >> 8;
1340 						break;
1341 					}
1342 
1343 					case BLEND_OPAQUE3:
1344 					{
1345 						outr = (srcr * i8) >> 8;
1346 						outg = (srcg * i8) >> 8;
1347 						outb = (srcb * i8) >> 8;
1348 						break;
1349 					}
1350 
1351 					case BLEND_OPAQUE4:
1352 					{
1353 						outr = srcr;
1354 						outg = srcg;
1355 						outb = srcb;
1356 						break;
1357 					}
1358 
1359 					case BLEND_OPAQUE5:
1360 					{
1361 						// TODO: Fog factor?
1362 						outr = (srcr * srca) >> 8;
1363 						outg = (srcg * srca) >> 8;
1364 						outb = (srcb * srca) >> 8;
1365 						break;
1366 					}
1367 
1368 					case BLEND_ADD1:
1369 					{
1370 						outr = ((srcr * srca) >> 8) + dstr;
1371 						outg = ((srcg * srca) >> 8) + dstg;
1372 						outb = ((srcb * srca) >> 8) + dstb;
1373 						break;
1374 					}
1375 
1376 					case BLEND_ADD2:
1377 					{
1378 						outr = ((srcr * srca) >> 8) + ((dstr * (dsta << 1)) >> 8);
1379 						outg = ((srcg * srca) >> 8) + ((dstg * (dsta << 1)) >> 8);
1380 						outb = ((srcb * srca) >> 8) + ((dstb * (dsta << 1)) >> 8);
1381 						break;
1382 					}
1383 
1384 					case BLEND_MUL1:
1385 					{
1386 						outr = (((srcr * (srca << 1)) >> 8) * dstr) >> 8;
1387 						outg = (((srcg * (srca << 1)) >> 8) * dstg) >> 8;
1388 						outb = (((srcb * (srca << 1)) >> 8) * dstb) >> 8;
1389 						break;
1390 					}
1391 					default:
1392 					{
1393 						outr = srcr;
1394 						outg = srcg;
1395 						outb = srcb;
1396 						break;
1397 					}
1398 				}
1399 
1400 				outr = outr > 0xff ? 0xff : outr;
1401 				outg = outg > 0xff ? 0xff : outg;
1402 				outb = outb > 0xff ? 0xff : outb;
1403 
1404 				outr >>= 3;
1405 				outg >>= 3;
1406 				outb >>= 3;
1407 
1408 				WAVERAM_WRITEPIX(m_state.m_zeus_renderbase, scanline, x, (outr << 10) | (outg << 5) | outb);
1409 
1410 				if (object.depth_write_enable)
1411 					*depthptr = depth;
1412 			}
1413 		}
1414 
1415 		curz += dzdx;
1416 		curu += dudx;
1417 		curv += dvdx;
1418 		curi += didx;
1419 	}
1420 }
1421 
1422 
1423 
render_poly_solid_fixedz(int32_t scanline,const extent_t & extent,const mz_poly_extra_data & object,int threadid)1424 void midzeus_renderer::render_poly_solid_fixedz(int32_t scanline, const extent_t& extent, const mz_poly_extra_data& object, int threadid)
1425 {
1426 	uint16_t color = object.solidcolor;
1427 	uint16_t depth = object.zoffset;
1428 	int x;
1429 
1430 	for (x = extent.startx; x < extent.stopx; x++)
1431 		m_state.waveram_plot_depth(scanline, x, color, depth);
1432 }
1433 
1434 
1435 
1436 /*************************************
1437  *
1438  *  Debugging tools
1439  *
1440  *************************************/
1441 
log_fifo_command(const uint32_t * data,int numwords,const char * suffix)1442 void midzeus_state::log_fifo_command(const uint32_t *data, int numwords, const char *suffix)
1443 {
1444 	int wordnum;
1445 
1446 	logerror("Zeus cmd %02X :", data[0] >> 24);
1447 	for (wordnum = 0; wordnum < numwords; wordnum++)
1448 		logerror(" %08X", data[wordnum]);
1449 	logerror("%s", suffix);
1450 }
1451 
1452 
log_waveram(uint32_t length_and_base)1453 void midzeus_state::log_waveram(uint32_t length_and_base)
1454 {
1455 	static struct
1456 	{
1457 		uint32_t lab;
1458 		uint32_t checksum;
1459 	} recent_entries[100];
1460 
1461 	uint32_t numoctets = (length_and_base >> 24) + 1;
1462 	const uint32_t *ptr = (const uint32_t *)waveram0_ptr_from_block_addr(length_and_base);
1463 	uint32_t checksum = length_and_base;
1464 	int foundit = false;
1465 	int i;
1466 
1467 	for (i = 0; i < numoctets; i++)
1468 		checksum += ptr[i*2] + ptr[i*2+1];
1469 
1470 	for (i = 0; i < ARRAY_LENGTH(recent_entries); i++)
1471 		if (recent_entries[i].lab == length_and_base && recent_entries[i].checksum == checksum)
1472 		{
1473 			foundit = true;
1474 			break;
1475 		}
1476 
1477 	if (i == ARRAY_LENGTH(recent_entries))
1478 		i--;
1479 	if (i != 0)
1480 	{
1481 		memmove(&recent_entries[1], &recent_entries[0], i * sizeof(recent_entries[0]));
1482 		recent_entries[0].lab = length_and_base;
1483 		recent_entries[0].checksum = checksum;
1484 	}
1485 	if (foundit)
1486 		return;
1487 
1488 	for (i = 0; i < numoctets; i++)
1489 		logerror("\t%02X: %08X %08X\n", i, ptr[i*2], ptr[i*2+1]);
1490 }
1491