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