From c0234a2f29c8c21cf77e581cc05a24fc1a824886 Mon Sep 17 00:00:00 2001 From: Ville Linde Date: Sun, 12 Oct 2014 00:28:50 +0000 Subject: [PATCH] model3: New 3D renderer + various fixes (still heavily WIP) [Ville Linde] --- .gitattributes | 1 - src/mame/drivers/model3.c | 171 +++--- src/mame/includes/model3.h | 103 ++-- src/mame/machine/model3.c | 129 ++-- src/mame/mame.mak | 1 - src/mame/video/m3raster.inc | 286 --------- src/mame/video/model3.c | 1109 +++++++++++++++++++++++++++-------- 7 files changed, 1072 insertions(+), 728 deletions(-) delete mode 100644 src/mame/video/m3raster.inc diff --git a/.gitattributes b/.gitattributes index c6e588d4dee..1b2384f8062 100644 --- a/.gitattributes +++ b/.gitattributes @@ -7597,7 +7597,6 @@ src/mame/video/lvcards.c svneol=native#text/plain src/mame/video/lwings.c svneol=native#text/plain src/mame/video/m10.c svneol=native#text/plain src/mame/video/m107.c svneol=native#text/plain -src/mame/video/m3raster.inc svneol=native#text/plain src/mame/video/m52.c svneol=native#text/plain src/mame/video/m57.c svneol=native#text/plain src/mame/video/m58.c svneol=native#text/plain diff --git a/src/mame/drivers/model3.c b/src/mame/drivers/model3.c index 5a66ad1cae1..c0e838e7f69 100644 --- a/src/mame/drivers/model3.c +++ b/src/mame/drivers/model3.c @@ -13,34 +13,36 @@ Step 2.1: 166 MHz PPC, same 3D engine as 2.0, differences unknown Game status: - vf3/vf3a/vf3tb - don't boot - stuck in poly_wait() - bass - boots and runs with 3D + vf3/vf3a/vf3tb - crashes + bass - works getbass - I/O board error (?) - scud/scuda - boots and runs with 3D (scuda says "for sale and use only in Japan" but is marked Export?) - scudj - boots but hangs up (no SCSI IRQs) - scudp - shows initial screen, apparently won't go into test mode or advance - lostwsga - SCSI IRQ stuck on (boots and runs with 3D if hacked) - vs215 - boots and runs with 3D - lemans24 - SCSI IRQ stuck on (boots if hacked) - vs29815 - write to unknown 53c810 SCSI register + scud/scuda - works (scuda says "for sale and use only in Japan" but is marked Export?) + scudj - works + scudplus - works + lostwsga - works + vs215 - works + lemans24 - works + vs29815 - massive memory trashing and page faults - vs2 - looks like it should boot but never displays anything - harley - boots and runs with 3D after a "NO DAUGHTER BOARD DETECTED" error - skichamp - "NO DAUGHTER BOARD DETECTED", doesn't advance (no SCSI IRQs occur) - srally2/sraly2dx - doesn't boot (no SCSI IRQs occur, other IRQs look fine) - von2/von254g - SCSI IRQ stuck on (boots and runs if SCSI ack is hacked) - fvipers2 - says "ONE PROCESSOR DETECTED" and hangs (no SCSI IRQs occur, others look fine) - vs298/vs299/vs2v991 - hangs (no SCSI IRQs occur, others look fine) + vs2 - waiting for decrementer (same code as eca) + harley - + skichamp - waiting for decrementer + srally2/sraly2dx - works + von2/von254g - works + fvipers2 - waiting for decrementer (same code as eca) + vs298/vs299/vs2v991 - waiting for decrementer + oceanhun - same as daytona2 + lamachin - works dayto2pe - bug in DRC MMU page-fault handling, causes infinite loop at PC:0x2270 (or debug assert) daytona2 - As above. spikeout/spikeofe - As above. - dirtdvls/dirtdvla - SCSI IRQ stuck on (boots partially if hacked) - swtrilgy - doesn't boot (no SCSI IRQs occur, other IRQs look fine) - swtrilga - SCSI IRQ stuck on - magtruck - SCSI IRQ stuck on (boots and fails country code check (!) if hacked) - eca/ecax - doesn't boot (a few SCSI IRQs occur but then cease, other IRQs look fine) + dirtdvls/dirtdvla - works + swtrilgy - + swtrilga - + magtruck - works + eca/ecax - waiting for decrementer =================================================================================== @@ -1242,10 +1244,9 @@ void model3_state::model3_init(int step) m_m3_step = step; // step = BCD hardware rev. 0x10 for 1.0, 0x15 for 1.5, 0x20 for 2.0, etc. tap_reset(); - if (step < 0x20) { - if( core_stricmp(machine().system().name, "vs215") == 0 || - core_stricmp(machine().system().name, "vs29815") == 0 || - core_stricmp(machine().system().name, "bass") == 0 ) + if (step < 0x20) + { + if (m_step15_with_mpc106) { mpc106_init(machine()); } @@ -1255,12 +1256,12 @@ void model3_state::model3_init(int step) } m_real3d_device_id = 0x16c311db; /* PCI Vendor ID (11db = SEGA), Device ID (16c3 = 315-5827) */ } - else { + else + { mpc106_init(machine()); // some step 2+ games need the older PCI ID (obvious symptom: // vbl is enabled briefly then disabled so the game hangs) - if (core_stricmp(machine().system().name, "magtruck") == 0 || - core_stricmp(machine().system().name, "von254g") == 0) + if (m_step20_with_old_real3d) { m_real3d_device_id = 0x16c311db; /* PCI Vendor ID (11db = SEGA), Device ID (16c3 = 315-5827) */ } @@ -5646,84 +5647,51 @@ DRIVER_INIT_MEMBER(model3_state,lostwsga) DRIVER_INIT_MEMBER(model3_state,scud) { - UINT32 *rom = (UINT32*)memregion("user1")->base(); - DRIVER_INIT_CALL(model3_15); /* TODO: network device at 0xC0000000 - FF */ m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0xf9000000, 0xf90000ff, read64_delegate(FUNC(model3_state::scsi_r),this), write64_delegate(FUNC(model3_state::scsi_w),this)); - - rom[(0x71275c^4)/4] = 0x60000000; - rom[(0x71277c^4)/4] = 0x60000000; } DRIVER_INIT_MEMBER(model3_state,scudplus) { - UINT32 *rom = (UINT32*)memregion("user1")->base(); - DRIVER_INIT_CALL(model3_15); /* TODO: network device at 0xC0000000 - FF */ m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0xc1000000, 0xc10000ff, read64_delegate(FUNC(model3_state::scsi_r),this), write64_delegate(FUNC(model3_state::scsi_w),this)); - - rom[(0x713724^4)/4] = 0x60000000; - rom[(0x713744^4)/4] = 0x60000000; - - rom[(0x741f48^4)/4] = 0x60000000; - - rom[(0x741f68^4)/4] = 0x60000000; - rom[(0x741efc^4)/4] = 0x60000000; } DRIVER_INIT_MEMBER(model3_state,scudplusa) { - //UINT32 *rom = (UINT32*)memregion("user1")->base(); - DRIVER_INIT_CALL(model3_15); /* TODO: network device at 0xC0000000 - FF */ m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0xc1000000, 0xc10000ff, read64_delegate(FUNC(model3_state::scsi_r),this), write64_delegate(FUNC(model3_state::scsi_w),this)); - - //rom[(0x713724^4)/4] = 0x60000000; // Fix ME!!!! Needs to corrected for the non REV A version!!!! - //rom[(0x713744^4)/4] = 0x60000000; - - //rom[(0x741f48^4)/4] = 0x60000000; - - //rom[(0x741f68^4)/4] = 0x60000000; - //rom[(0x741efc^4)/4] = 0x60000000; } DRIVER_INIT_MEMBER(model3_state,lemans24) { - UINT32 *rom = (UINT32*)memregion("user1")->base(); DRIVER_INIT_CALL(model3_15); m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0xc1000000, 0xc10000ff, read64_delegate(FUNC(model3_state::scsi_r),this), write64_delegate(FUNC(model3_state::scsi_w),this)); - - rom[(0x73fe38^4)/4] = 0x38840004; /* This seems to be an actual bug in the original code */ - - rom[(0x73eb5c^4)/4] = 0x60000000; - rom[(0x73edd0^4)/4] = 0x60000000; - rom[(0x73edc4^4)/4] = 0x60000000; + +// rom[(0x73fe38^4)/4] = 0x38840004; /* This seems to be an actual bug in the original code */ } DRIVER_INIT_MEMBER(model3_state,vf3) { - UINT32 *rom = (UINT32*)memregion("user1")->base(); + //UINT32 *rom = (UINT32*)memregion("user1")->base(); DRIVER_INIT_CALL(model3_10); + /* rom[(0x713c7c^4)/4] = 0x60000000; rom[(0x713e54^4)/4] = 0x60000000; rom[(0x7125b0^4)/4] = 0x60000000; rom[(0x7125d0^4)/4] = 0x60000000; - + */ } DRIVER_INIT_MEMBER(model3_state,vs215) { - UINT32 *rom = (UINT32*)memregion("user1")->base(); - - rom[(0x70dde0^4)/4] = 0x60000000; - rom[(0x70e6f0^4)/4] = 0x60000000; - rom[(0x70e710^4)/4] = 0x60000000; + m_step15_with_mpc106 = true; interleave_vroms(machine()); m_maincpu->space(AS_PROGRAM).install_read_bank(0xff000000, 0xff7fffff, "bank1" ); @@ -5739,6 +5707,8 @@ DRIVER_INIT_MEMBER(model3_state,vs215) DRIVER_INIT_MEMBER(model3_state,vs29815) { + m_step15_with_mpc106 = true; + UINT32 *rom = (UINT32*)memregion("user1")->base(); rom[(0x6028ec^4)/4] = 0x60000000; @@ -5758,10 +5728,7 @@ DRIVER_INIT_MEMBER(model3_state,vs29815) DRIVER_INIT_MEMBER(model3_state,bass) { - UINT32 *rom = (UINT32*)memregion("user1")->base(); - - rom[(0x7999a8^4)/4] = 0x60000000; - rom[(0x7999c8^4)/4] = 0x60000000; + m_step15_with_mpc106 = true; interleave_vroms(machine()); m_maincpu->space(AS_PROGRAM).install_read_bank(0xff000000, 0xff7fffff, "bank1" ); @@ -5865,72 +5832,70 @@ DRIVER_INIT_MEMBER(model3_state,harley) DRIVER_INIT_MEMBER(model3_state,harleya) { - UINT32 *rom = (UINT32*)memregion("user1")->base(); + //UINT32 *rom = (UINT32*)memregion("user1")->base(); DRIVER_INIT_CALL(model3_20); m_network_ram = auto_alloc_array_clear(machine(), UINT64, 0x10000); m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0xc0000000, 0xc00fffff, read64_delegate(FUNC(model3_state::network_r),this), write64_delegate(FUNC(model3_state::network_w),this)); + /* rom[(0x50e8d4^4)/4] = 0x60000000; rom[(0x50e8f4^4)/4] = 0x60000000; rom[(0x50fb84^4)/4] = 0x60000000; rom[(0x4f736c^4)/4] = 0x60000000; rom[(0x4f738c^4)/4] = 0x60000000; + */ } DRIVER_INIT_MEMBER(model3_state,srally2) -{ - UINT32 *rom = (UINT32*)memregion("user1")->base(); +{ DRIVER_INIT_CALL(model3_20); + + UINT32 *rom = (UINT32*)memregion("user1")->base(); rom[(0x7c0c4^4)/4] = 0x60000000; rom[(0x7c0c8^4)/4] = 0x60000000; rom[(0x7c0cc^4)/4] = 0x60000000; + // Writes command 000023FFFFFFFFFE to JTAG, expects result 0x0040000000 (41 bits) + // Writes command 000003FFFFFFFFFE + // Writes command 00003FFFFFFFFFFE 248 times + // Writes command 000023FFFFFFFFFE, expects result 0x01000000000 (?? bits) } DRIVER_INIT_MEMBER(model3_state,swtrilgy) { - UINT32 *rom = (UINT32*)memregion("user1")->base(); + //UINT32 *rom = (UINT32*)memregion("user1")->base(); DRIVER_INIT_CALL(model3_20); + /* rom[(0xf0e48^4)/4] = 0x60000000; rom[(0x043dc^4)/4] = 0x48000090; rom[(0x029a0^4)/4] = 0x60000000; rom[(0x02a0c^4)/4] = 0x60000000; + */ } DRIVER_INIT_MEMBER(model3_state,swtrilga) { - UINT32 *rom = (UINT32*)memregion("user1")->base(); + //UINT32 *rom = (UINT32*)memregion("user1")->base(); DRIVER_INIT_CALL(model3_20); - rom[(0xf6dd0^4)/4] = 0x60000000; + //rom[(0xf6dd0^4)/4] = 0x60000000; } DRIVER_INIT_MEMBER(model3_state,von2) { - UINT32 *rom = (UINT32*)memregion("user1")->base(); + m_step20_with_old_real3d = true; + DRIVER_INIT_CALL(model3_20); - - rom[(0x189168^4)/4] = 0x60000000; - rom[(0x1890ac^4)/4] = 0x60000000; - rom[(0x1890b8^4)/4] = 0x60000000; - rom[(0x1888a8^4)/4] = 0x60000000; - rom[(0x1891c8^4)/4] = 0x60000000; } DRIVER_INIT_MEMBER(model3_state,dirtdvls) { - UINT32 *rom = (UINT32*)memregion("user1")->base(); - DRIVER_INIT_CALL(model3_20); + m_step20_with_old_real3d = true; - rom[(0x0600a0^4)/4] = 0x60000000; - rom[(0x0608a4^4)/4] = 0x60000000; - rom[(0x0608b0^4)/4] = 0x60000000; - rom[(0x060960^4)/4] = 0x60000000; - rom[(0x0609c0^4)/4] = 0x60000000; - rom[(0x001e24^4)/4] = 0x60000000; + DRIVER_INIT_CALL(model3_20); } DRIVER_INIT_MEMBER(model3_state,daytona2) @@ -5982,23 +5947,26 @@ DRIVER_INIT_MEMBER(model3_state,spikeofe) DRIVER_INIT_MEMBER(model3_state,eca) { - UINT32 *rom = (UINT32*)memregion("user1")->base(); +// UINT32 *rom = (UINT32*)memregion("user1")->base(); DRIVER_INIT_CALL(model3_20); - + /* rom[(0x535560^4)/4] = 0x60000000; rom[(0x535580^4)/4] = 0x60000000; + */ } DRIVER_INIT_MEMBER(model3_state,skichamp) { - UINT32 *rom = (UINT32*)memregion("user1")->base(); + //UINT32 *rom = (UINT32*)memregion("user1")->base(); DRIVER_INIT_CALL(model3_20); + /* rom[(0x5263c8^4)/4] = 0x60000000; rom[(0x5263e8^4)/4] = 0x60000000; rom[(0x516bbc^4)/4] = 0x60000000; rom[(0x516b9c^4)/4] = 0x60000000; // decrementer + */ } DRIVER_INIT_MEMBER(model3_state,oceanhun) @@ -6011,6 +5979,15 @@ DRIVER_INIT_MEMBER(model3_state,oceanhun) DRIVER_INIT_MEMBER(model3_state,magtruck) { + m_step20_with_old_real3d = true; + + DRIVER_INIT_CALL(model3_20); +} + +DRIVER_INIT_MEMBER(model3_state,lamachin) +{ + m_step20_with_old_real3d = true; + DRIVER_INIT_CALL(model3_20); } @@ -6039,13 +6016,13 @@ GAME( 1998, vs29815, vs298, model3_15, model3, model3_state, vs29815, ROT0 GAME( 1997, vs2, 0, model3_20, model3, model3_state, vs2, ROT0, "Sega", "Virtua Striker 2 (Step 2.0)", GAME_NOT_WORKING | GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) GAME( 1997, harley, 0, model3_20, harley, model3_state, harley, ROT0, "Sega", "Harley-Davidson and L.A. Riders (Revision B)", GAME_NOT_WORKING | GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) GAME( 1997, harleya, harley, model3_20, harley, model3_state, harleya, ROT0, "Sega", "Harley-Davidson and L.A. Riders (Revision A)", GAME_NOT_WORKING | GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) -GAME( 1998, lamachin, 0, model3_20, model3, model3_state, model3_20, ROT0, "Sega", "L.A. Machineguns", GAME_NOT_WORKING | GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) +GAME( 1998, lamachin, 0, model3_20, model3, model3_state, lamachin, ROT0, "Sega", "L.A. Machineguns", GAME_NOT_WORKING | GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) GAME( 1998, oceanhun, 0, model3_20, model3, model3_state, oceanhun, ROT0, "Sega", "The Ocean Hunter", GAME_NOT_WORKING | GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) GAME( 1998, skichamp, 0, model3_20, skichamp, model3_state, skichamp, ROT0, "Sega", "Ski Champ", GAME_NOT_WORKING | GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) GAME( 1998, srally2, 0, model3_20, scud, model3_state, srally2, ROT0, "Sega", "Sega Rally 2", GAME_NOT_WORKING | GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) GAME( 1998, srally2x, 0, model3_20, scud, model3_state, srally2, ROT0, "Sega", "Sega Rally 2 DX", GAME_NOT_WORKING | GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) GAME( 1998, von2, 0, model3_20, model3, model3_state, von2, ROT0, "Sega", "Virtual On 2: Oratorio Tangram (Revision B)", GAME_NOT_WORKING | GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) -GAME( 1998, von254g, von2, model3_20, model3, model3_state, model3_20, ROT0, "Sega", "Virtual On 2: Oratorio Tangram (ver 5.4g)", GAME_NOT_WORKING | GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) +GAME( 1998, von254g, von2, model3_20, model3, model3_state, von2, ROT0, "Sega", "Virtual On 2: Oratorio Tangram (ver 5.4g)", GAME_NOT_WORKING | GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) GAME( 1998, fvipers2, 0, model3_20, model3, model3_state, model3_20, ROT0, "Sega", "Fighting Vipers 2 (Revision A)", GAME_NOT_WORKING | GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) GAME( 1998, vs298, 0, model3_20, model3, model3_state, vs298, ROT0, "Sega", "Virtua Striker 2 '98 (Step 2.0)", GAME_NOT_WORKING | GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) GAME( 1999, vs2v991, 0, model3_20, model3, model3_state, vs2v991, ROT0, "Sega", "Virtua Striker 2 '99.1 (Revision B)", GAME_NOT_WORKING | GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND ) diff --git a/src/mame/includes/model3.h b/src/mame/includes/model3.h index 3eecdda208d..39722e92eba 100644 --- a/src/mame/includes/model3.h +++ b/src/mame/includes/model3.h @@ -1,4 +1,4 @@ -#include "video/polylgcy.h" +#include "video/poly.h" #include "bus/scsi/scsi.h" #include "machine/53c810.h" #include "audio/dsbz80.h" @@ -9,11 +9,58 @@ typedef float MATRIX[4][4]; typedef float VECTOR[4]; typedef float VECTOR3[3]; -struct PLANE { - float x,y,z,d; +struct cached_texture +{ + cached_texture *next; + UINT8 width; + UINT8 height; + UINT8 format; + UINT8 alpha; + rgb_t data[1]; }; -struct cached_texture; +struct m3_plane +{ + float x; + float y; + float z; + float d; +}; + +struct m3_vertex +{ + float x; + float y; + float z; + float u; + float v; + float nx; + float ny; + float nz; +}; + +struct m3_clip_vertex +{ + float x; + float y; + float z; + float u; + float v; + float i; +}; + +struct m3_triangle +{ + m3_clip_vertex v[3]; + + cached_texture *texture; + int param; + int transparency; + int intensity; + int color; +}; + +class model3_renderer; class model3_state : public driver_device { @@ -31,18 +78,11 @@ public: m_dsbz80(*this, DSBZ80_TAG), m_soundram(*this, "soundram"), m_gfxdecode(*this, "gfxdecode"), - m_palette(*this, "palette") { } - - struct TRIANGLE + m_palette(*this, "palette") { - poly_vertex v[3]; - UINT8 texture_x, texture_y; - UINT8 texture_width, texture_height; - UINT8 transparency; - UINT8 texture_format, param; - int intensity; - UINT32 color; - }; + m_step15_with_mpc106 = false; + m_step20_with_old_real3d = false; + } required_device m_maincpu; optional_device m_lsi53c810; @@ -54,7 +94,7 @@ public: required_shared_ptr m_work_ram; required_shared_ptr m_paletteram64; optional_device m_dsbz80; // Z80-based MPEG Digital Sound Board - required_shared_ptr m_soundram; + required_shared_ptr m_soundram; required_device m_gfxdecode; required_device m_palette; @@ -69,13 +109,15 @@ public: UINT8 m_scsi_irq_state; int m_crom_bank; int m_controls_bank; + bool m_step15_with_mpc106; + bool m_step20_with_old_real3d; UINT32 m_real3d_device_id; - UINT32 m_mpc105_regs[0x40]; - UINT32 m_mpc105_addr; int m_pci_bus; int m_pci_device; int m_pci_function; int m_pci_reg; + UINT32 m_mpc105_regs[0x40]; + UINT32 m_mpc105_addr; UINT32 m_mpc106_regs[0x40]; UINT32 m_mpc106_addr; UINT32 m_dma_data; @@ -117,19 +159,14 @@ public: UINT32 *m_culling_ram; UINT32 *m_polygon_ram; int m_real3d_display_list; - bitmap_rgb32 m_bitmap3d; - bitmap_ind32 m_zbuffer; rectangle m_clip3d; rectangle *m_screen_clip; VECTOR3 m_parallel_light; float m_parallel_light_intensity; float m_ambient_light_intensity; - legacy_poly_manager *m_poly; - int m_list_depth; - int m_tick; - int m_debug_layer_disable; UINT64 m_vid_reg0; int m_matrix_stack_ptr; + int m_list_depth; MATRIX *m_matrix_stack; MATRIX m_coordinate_system; float m_viewport_focal_length; @@ -137,10 +174,12 @@ public: int m_viewport_region_y; int m_viewport_region_width; int m_viewport_region_height; - PLANE m_clip_plane[5]; + m3_plane m_clip_plane[5]; UINT32 m_matrix_base_address; cached_texture *m_texcache[2][1024/32][2048/32]; + model3_renderer *m_renderer; + DECLARE_READ32_MEMBER(rtc72421_r); DECLARE_WRITE32_MEMBER(rtc72421_w); DECLARE_READ64_MEMBER(model3_char_r); @@ -219,8 +258,8 @@ public: DECLARE_DRIVER_INIT(dayto2pe); DECLARE_DRIVER_INIT(spikeout); DECLARE_DRIVER_INIT(magtruck); - DECLARE_DRIVER_INIT(model3_15); - virtual void video_start(); + DECLARE_DRIVER_INIT(lamachin); + DECLARE_DRIVER_INIT(model3_15); DECLARE_MACHINE_START(model3_10); DECLARE_MACHINE_RESET(model3_10); DECLARE_MACHINE_START(model3_15); @@ -229,7 +268,6 @@ public: DECLARE_MACHINE_RESET(model3_20); DECLARE_MACHINE_START(model3_21); DECLARE_MACHINE_RESET(model3_21); - UINT32 screen_update_model3(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); TIMER_CALLBACK_MEMBER(model3_sound_timer_tick); TIMER_DEVICE_CALLBACK_MEMBER(model3_interrupt); void model3_exit(); @@ -241,6 +279,8 @@ public: void set_irq_line(UINT8 bit, int line); void model3_init(int step); // video + virtual void video_start(); + UINT32 screen_update_model3(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); TILE_GET_INFO_MEMBER(tile_info_layer0_4bit); TILE_GET_INFO_MEMBER(tile_info_layer1_4bit); TILE_GET_INFO_MEMBER(tile_info_layer2_4bit); @@ -262,7 +302,6 @@ public: void pop_matrix_stack(); void multiply_matrix_stack(MATRIX matrix); void translate_matrix_stack(float x, float y, float z); - void render_one(TRIANGLE *tri); void draw_model(UINT32 addr); UINT32 *get_memory_pointer(UINT32 address); void load_matrix(int matrix_num, MATRIX *out); @@ -272,11 +311,6 @@ public: void draw_block(UINT32 address); void draw_viewport(int pri, UINT32 address); void real3d_traverse_display_list(); -#ifdef UNUSED_FUNCTION - inline void write_texture8(int xpos, int ypos, int width, int height, int page, UINT16 *data); - void draw_texture_sheet(bitmap_ind16 &bitmap, const rectangle &cliprect); - void copy_screen(bitmap_ind16 &bitmap, const rectangle &cliprect); -#endif void real3d_display_list_end(); void real3d_display_list1_dma(UINT32 src, UINT32 dst, int length, int byteswap); void real3d_display_list2_dma(UINT32 src, UINT32 dst, int length, int byteswap); @@ -288,4 +322,5 @@ public: int tap_read(); void tap_write(int tck, int tms, int tdi, int trst); void tap_reset(); + void tap_set_asic_ids(); }; diff --git a/src/mame/machine/model3.c b/src/mame/machine/model3.c index 6d28e7e0e6b..d679424c561 100644 --- a/src/mame/machine/model3.c +++ b/src/mame/machine/model3.c @@ -148,57 +148,27 @@ void model3_state::tap_write(int tck, int tms, int tdi, int trst) switch (m_tap_state) { case 3: // Capture-DR + //printf("capture dr (IR = %08X%08X\n", (UINT32)(m_ir >> 32),(UINT32)(m_ir)); - /* - * Read ASIC IDs. - * - * The ID Sequence is: - * - Jupiter - * - Mercury - * - Venus - * - Earth - * - Mars - * - Mars (again) - * - * Note that different Model 3 steps have different chip - * revisions, hence the different IDs returned below. - * - * On Step 1.5 and 1.0, instruction 0x0C631F8C7FFE is used to retrieve - * the ID codes but Step 2.0 is a little weirder. It seems to use this - * and either the state of the TAP after reset or other instructions - * to read the IDs as well. This can be emulated in one of 2 ways: - * Ignore the instruction and always load up the data or load the - * data on TAP reset and when the instruction is issued. - */ + if (m_ir == U64(0x000023fffffffffe)) + { + for (int i=0; i < 32; i++) + { + m_id_data[i] = 0; + } - if (m_m3_step == 0x10) - { - insert_id(0x116C7057, 1 + 0 * 32); - insert_id(0x216C3057, 1 + 1 * 32); - insert_id(0x116C4057, 1 + 2 * 32); - insert_id(0x216C5057, 1 + 3 * 32); - insert_id(0x116C6057, 1 + 4 * 32 + 1); - insert_id(0x116C6057, 1 + 5 * 32 + 1); - } - else if (m_m3_step == 0x15) - { - insert_id(0x316C7057, 1 + 0 * 32); - insert_id(0x316C3057, 1 + 1 * 32); - insert_id(0x216C4057, 1 + 2 * 32); // Lost World may to use 0x016C4057 - insert_id(0x316C5057, 1 + 3 * 32); - insert_id(0x216C6057, 1 + 4 * 32 + 1); - insert_id(0x216C6057, 1 + 5 * 32 + 1); - } - else if (m_m3_step >= 0x20) - { - insert_id(0x416C7057, 1 + 0 * 32); - insert_id(0x416C3057, 1 + 1 * 32); - insert_id(0x316C4057, 1 + 2 * 32); - insert_id(0x416C5057, 1 + 3 * 32); - insert_id(0x316C6057, 1 + 4 * 32 + 1); - insert_id(0x316C6057, 1 + 5 * 32 + 1); - } + m_id_size = 41; + UINT64 res = 0x0040000000; + + int start_bit = 0; + for (int i = 41; i >= 0; i--) + insert_bit(m_id_data, start_bit++, ((UINT64)(1 << i) & res) ? 1 : 0); + } + else if (m_ir == U64(0x00000c631f8c7ffe)) + { + tap_set_asic_ids(); + } break; case 4: // Shift-DR @@ -241,6 +211,66 @@ void model3_state::tap_write(int tck, int tms, int tdi, int trst) } } +void model3_state::tap_set_asic_ids() +{ + /* + * Read ASIC IDs. + * + * The ID Sequence is: + * - Jupiter + * - Mercury + * - Venus + * - Earth + * - Mars + * - Mars (again) + * + * Note that different Model 3 steps have different chip + * revisions, hence the different IDs returned below. + * + * On Step 1.5 and 1.0, instruction 0x0C631F8C7FFE is used to retrieve + * the ID codes but Step 2.0 is a little weirder. It seems to use this + * and either the state of the TAP after reset or other instructions + * to read the IDs as well. This can be emulated in one of 2 ways: + * Ignore the instruction and always load up the data or load the + * data on TAP reset and when the instruction is issued. + */ + + for (int i=0; i < 32; i++) + { + m_id_data[i] = 0; + } + + if (m_m3_step == 0x10) + { + insert_id(0x116C7057, 1 + 0 * 32); + insert_id(0x216C3057, 1 + 1 * 32); + insert_id(0x116C4057, 1 + 2 * 32); + insert_id(0x216C5057, 1 + 3 * 32); + insert_id(0x116C6057, 1 + 4 * 32 + 1); + insert_id(0x116C6057, 1 + 5 * 32 + 1); + } + else if (m_m3_step == 0x15) + { + insert_id(0x316C7057, 1 + 0 * 32); + insert_id(0x316C3057, 1 + 1 * 32); + insert_id(0x216C4057, 1 + 2 * 32); // Lost World may to use 0x016C4057 + insert_id(0x316C5057, 1 + 3 * 32); + insert_id(0x216C6057, 1 + 4 * 32 + 1); + insert_id(0x216C6057, 1 + 5 * 32 + 1); + } + else if (m_m3_step >= 0x20) + { + insert_id(0x416C7057, 1 + 0 * 32); + insert_id(0x416C3057, 1 + 1 * 32); + insert_id(0x316C4057, 1 + 2 * 32); + insert_id(0x416C5057, 1 + 3 * 32); + insert_id(0x316C6057, 1 + 4 * 32 + 1); + insert_id(0x316C6057, 1 + 5 * 32 + 1); + } + + m_id_size = 197; // 197 bits +} + /* * void tap_reset(void); @@ -250,8 +280,9 @@ void model3_state::tap_write(int tck, int tms, int tdi, int trst) void model3_state::tap_reset() { - m_id_size = 197; // 197 bits m_tap_state = 0; // test-logic/reset + + tap_set_asic_ids(); } /*****************************************************************************/ diff --git a/src/mame/mame.mak b/src/mame/mame.mak index a36792813bb..6eb7abe5f91 100644 --- a/src/mame/mame.mak +++ b/src/mame/mame.mak @@ -2943,7 +2943,6 @@ $(DRIVERS)/model1.o: $(MAMESRC)/includes/model1.h $(MAMESRC)/audio/dsbz80.h $(VIDEO)/model1.o: $(MAMESRC)/includes/model1.h $(MAMESRC)/audio/dsbz80.h $(MACHINE)/model1.o: $(MAMESRC)/includes/model1.h $(MAMESRC)/audio/dsbz80.h $(VIDEO)/model2.o: $(MAMESRC)/video/model2rd.inc -$(VIDEO)/model3.o: $(MAMESRC)/video/m3raster.inc $(VIDEO)/n64.o: $(MAMESRC)/video/rdpfiltr.inc $(DRIVERS)/bfm_sc4.o: $(MAMESRC)/includes/bfm_sc45.h $(DRIVERS)/bfm_sc5.o: $(MAMESRC)/includes/bfm_sc45.h diff --git a/src/mame/video/m3raster.inc b/src/mame/video/m3raster.inc deleted file mode 100644 index 7c5f49612bf..00000000000 --- a/src/mame/video/m3raster.inc +++ /dev/null @@ -1,286 +0,0 @@ -static void draw_scanline_normal(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid) -{ - const poly_extra_data *extra = (const poly_extra_data *)extradata; - const cached_texture *texture = extra->texture; - bitmap_rgb32 *destmap = (bitmap_rgb32 *)dest; - UINT32 *p = &destmap->pix32(scanline); - UINT32 *d = &extra->zbuffer->pix32(scanline); - float ooz = extent->param[0].start; - float uoz = extent->param[1].start; - float voz = extent->param[2].start; - float doozdx = extent->param[0].dpdx; - float duozdx = extent->param[1].dpdx; - float dvozdx = extent->param[2].dpdx; - UINT32 polyi = extra->polygon_intensity; - UINT32 umask = (((extra->texture_param & TRI_PARAM_TEXTURE_MIRROR_U) ? 64 : 32) << texture->width) - 1; - UINT32 vmask = (((extra->texture_param & TRI_PARAM_TEXTURE_MIRROR_V) ? 64 : 32) << texture->height) - 1; - UINT32 width = 6 + texture->width; - int x; - - for (x = extent->startx; x < extent->stopx; x++) - { - UINT32 iz = ooz * 256.0f; - if (iz > d[x]) - { - float z = 1.0f / ooz; - UINT32 u = uoz * z; - UINT32 v = voz * z; - UINT32 u1 = (u >> 8) & umask; - UINT32 v1 = (v >> 8) & vmask; - UINT32 u2 = (u1 + 1) & umask; - UINT32 v2 = (v1 + 1) & vmask; - UINT32 pix00 = texture->data[(v1 << width) + u1]; - UINT32 pix01 = texture->data[(v1 << width) + u2]; - UINT32 pix10 = texture->data[(v2 << width) + u1]; - UINT32 pix11 = texture->data[(v2 << width) + u2]; - UINT32 texel = rgba_bilinear_filter(pix00, pix01, pix10, pix11, u, v); - UINT32 fr = ((texel & 0x00ff0000) * polyi) >> 8; - UINT32 fg = ((texel & 0x0000ff00) * polyi) >> 8; - UINT32 fb = ((texel & 0x000000ff) * polyi) >> 8; - p[x] = 0xff000000 | (fr & 0xff0000) | (fg & 0xff00) | (fb & 0xff); - d[x] = iz; - } - - ooz += doozdx; - uoz += duozdx; - voz += dvozdx; - } -} - -static void draw_scanline_trans(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid) -{ - const poly_extra_data *extra = (const poly_extra_data *)extradata; - const cached_texture *texture = extra->texture; - bitmap_rgb32 *destmap = (bitmap_rgb32 *)dest; - UINT32 *p = &destmap->pix32(scanline); - UINT32 *d = &extra->zbuffer->pix32(scanline); - float ooz = extent->param[0].start; - float uoz = extent->param[1].start; - float voz = extent->param[2].start; - float doozdx = extent->param[0].dpdx; - float duozdx = extent->param[1].dpdx; - float dvozdx = extent->param[2].dpdx; - UINT32 polyi = (extra->polygon_intensity * extra->polygon_transparency) >> 5; - int desttrans = 32 - extra->polygon_transparency; - UINT32 umask = (((extra->texture_param & TRI_PARAM_TEXTURE_MIRROR_U) ? 64 : 32) << texture->width) - 1; - UINT32 vmask = (((extra->texture_param & TRI_PARAM_TEXTURE_MIRROR_V) ? 64 : 32) << texture->height) - 1; - UINT32 width = 6 + texture->width; - int x; - - for (x = extent->startx; x < extent->stopx; x++) - { - UINT32 iz = ooz * 256.0f; - if (iz > d[x]) - { - float z = 1.0f / ooz; - UINT32 u = uoz * z; - UINT32 v = voz * z; - UINT32 u1 = (u >> 8) & umask; - UINT32 v1 = (v >> 8) & vmask; - UINT32 u2 = (u1 + 1) & umask; - UINT32 v2 = (v1 + 1) & vmask; - UINT32 pix00 = texture->data[(v1 << width) + u1]; - UINT32 pix01 = texture->data[(v1 << width) + u2]; - UINT32 pix10 = texture->data[(v2 << width) + u1]; - UINT32 pix11 = texture->data[(v2 << width) + u2]; - UINT32 texel = rgba_bilinear_filter(pix00, pix01, pix10, pix11, u, v); - UINT32 fr = ((texel & 0x00ff0000) * polyi) >> 8; - UINT32 fg = ((texel & 0x0000ff00) * polyi) >> 8; - UINT32 fb = ((texel & 0x000000ff) * polyi) >> 8; - UINT32 orig = p[x]; - fr += ((orig & 0x00ff0000) * desttrans) >> 5; - fg += ((orig & 0x0000ff00) * desttrans) >> 5; - fb += ((orig & 0x000000ff) * desttrans) >> 5; - p[x] = 0xff000000 | (fr & 0xff0000) | (fg & 0xff00) | (fb & 0xff); - d[x] = iz; - } - - ooz += doozdx; - uoz += duozdx; - voz += dvozdx; - } -} - - -static void draw_scanline_alpha(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid) -{ - const poly_extra_data *extra = (const poly_extra_data *)extradata; - const cached_texture *texture = extra->texture; - bitmap_rgb32 *destmap = (bitmap_rgb32 *)dest; - UINT32 *p = &destmap->pix32(scanline); - UINT32 *d = &extra->zbuffer->pix32(scanline); - float ooz = extent->param[0].start; - float uoz = extent->param[1].start; - float voz = extent->param[2].start; - float doozdx = extent->param[0].dpdx; - float duozdx = extent->param[1].dpdx; - float dvozdx = extent->param[2].dpdx; - UINT32 polyi = (extra->polygon_intensity * extra->polygon_transparency) >> 5; - int desttrans = 32 - extra->polygon_transparency; - UINT32 umask = (((extra->texture_param & TRI_PARAM_TEXTURE_MIRROR_U) ? 64 : 32) << texture->width) - 1; - UINT32 vmask = (((extra->texture_param & TRI_PARAM_TEXTURE_MIRROR_V) ? 64 : 32) << texture->height) - 1; - UINT32 width = 6 + texture->width; - int x; - - for (x = extent->startx; x < extent->stopx; x++) - { - UINT32 iz = ooz * 256.0f; - if (iz > d[x]) - { - float z = 1.0f / ooz; - UINT32 u = uoz * z; - UINT32 v = voz * z; - UINT32 u1 = (u >> 8) & umask; - UINT32 v1 = (v >> 8) & vmask; - UINT32 u2 = (u1 + 1) & umask; - UINT32 v2 = (v1 + 1) & vmask; - UINT32 pix00 = texture->data[(v1 << width) + u1]; - UINT32 pix01 = texture->data[(v1 << width) + u2]; - UINT32 pix10 = texture->data[(v2 << width) + u1]; - UINT32 pix11 = texture->data[(v2 << width) + u2]; - UINT32 texel = rgba_bilinear_filter(pix00, pix01, pix10, pix11, u, v); - UINT32 fa = texel >> 24; - if (fa != 0) - { - UINT32 combined = ((fa + 1) * polyi) >> 8; - UINT32 fr = ((texel & 0x00ff0000) * combined) >> (8+9); - UINT32 fg = ((texel & 0x0000ff00) * combined) >> (8+6); - UINT32 fb = ((texel & 0x000000ff) * combined) >> (8+3); - UINT32 orig = p[x]; - combined = ((255 - fa) * desttrans) >> 5; - fr += ((orig & 0x00ff0000) * combined) >> 8; - fg += ((orig & 0x0000ff00) * combined) >> 8; - fb += ((orig & 0x000000ff) * combined) >> 8; - p[x] = 0xff000000 | (fr & 0xff0000) | (fg & 0xff00) | (fb & 0xff); - d[x] = iz; - } - } - - ooz += doozdx; - uoz += duozdx; - voz += dvozdx; - } -} - - -static void draw_scanline_alpha_test(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid) -{ - const poly_extra_data *extra = (const poly_extra_data *)extradata; - const cached_texture *texture = extra->texture; - bitmap_rgb32 *destmap = (bitmap_rgb32 *)dest; - UINT32 *p = &destmap->pix32(scanline); - UINT32 *d = &extra->zbuffer->pix32(scanline); - float ooz = extent->param[0].start; - float uoz = extent->param[1].start; - float voz = extent->param[2].start; - float doozdx = extent->param[0].dpdx; - float duozdx = extent->param[1].dpdx; - float dvozdx = extent->param[2].dpdx; - UINT32 polyi = (extra->polygon_intensity * extra->polygon_transparency) >> 5; - int desttrans = 32 - extra->polygon_transparency; - UINT32 umask = (((extra->texture_param & TRI_PARAM_TEXTURE_MIRROR_U) ? 64 : 32) << texture->width) - 1; - UINT32 vmask = (((extra->texture_param & TRI_PARAM_TEXTURE_MIRROR_V) ? 64 : 32) << texture->height) - 1; - UINT32 width = 6 + texture->width; - int x; - - for (x = extent->startx; x < extent->stopx; x++) - { - UINT32 iz = ooz * 256.0f; - if (iz > d[x]) - { - float z = 1.0f / ooz; - UINT32 u = uoz * z; - UINT32 v = voz * z; - UINT32 u1 = (u >> 8) & umask; - UINT32 v1 = (v >> 8) & vmask; - UINT32 u2 = (u1 + 1) & umask; - UINT32 v2 = (v1 + 1) & vmask; - UINT32 pix00 = texture->data[(v1 << width) + u1]; - UINT32 pix01 = texture->data[(v1 << width) + u2]; - UINT32 pix10 = texture->data[(v2 << width) + u1]; - UINT32 pix11 = texture->data[(v2 << width) + u2]; - UINT32 texel = rgba_bilinear_filter(pix00, pix01, pix10, pix11, u, v); - UINT32 fa = texel >> 24; - if (fa >= 0xf8) - { - UINT32 combined = ((fa + 1) * polyi) >> 8; - UINT32 fr = ((texel & 0x00ff0000) * combined) >> (8+9); - UINT32 fg = ((texel & 0x0000ff00) * combined) >> (8+6); - UINT32 fb = ((texel & 0x000000ff) * combined) >> (8+3); - UINT32 orig = p[x]; - combined = ((255 - fa) * desttrans) >> 8; - fr += ((orig & 0x00ff0000) * combined) >> 5; - fg += ((orig & 0x0000ff00) * combined) >> 5; - fb += ((orig & 0x000000ff) * combined) >> 5; - p[x] = 0xff000000 | (fr & 0xff0000) | (fg & 0xff00) | (fb & 0xff); - d[x] = iz; - } - } - - ooz += doozdx; - uoz += duozdx; - voz += dvozdx; - } -} - -static void draw_scanline_color(void *dest, INT32 scanline, const poly_extent *extent, const void *extradata, int threadid) -{ - const poly_extra_data *extra = (const poly_extra_data *)extradata; - bitmap_rgb32 *destmap = (bitmap_rgb32 *)dest; - UINT32 *p = &destmap->pix32(scanline); - UINT32 *d = &extra->zbuffer->pix32(scanline); - float ooz = extent->param[0].start; - float doozdx = extent->param[0].dpdx; - int fr = (extra->color & 0x7c00) << 9; - int fg = (extra->color & 0x03e0) << 6; - int fb = (extra->color & 0x001f) << 3; - int x; - - // apply intensity - fr = (fr * extra->polygon_intensity) >> 8; - fg = (fg * extra->polygon_intensity) >> 8; - fb = (fb * extra->polygon_intensity) >> 8; - - /* simple case: no transluceny */ - if (extra->polygon_transparency >= 32) - { - UINT32 color = (fr & 0x7c00) | (fg & 0x03e0) | (fb & 0x1f); - for (x = extent->startx; x < extent->stopx; x++) - { - UINT32 iz = ooz * 256.0f; - if (iz > d[x]) - { - p[x] = color; - d[x] = iz; - } - ooz += doozdx; - } - } - - /* translucency */ - else - { - int polytrans = extra->polygon_transparency; - - fr = (fr * polytrans) >> 5; - fg = (fg * polytrans) >> 5; - fb = (fb * polytrans) >> 5; - polytrans = 32 - polytrans; - - for (x = extent->startx; x < extent->stopx; x++) - { - UINT32 iz = ooz * 256.0f; - if (iz > d[x]) - { - UINT32 orig = p[x]; - int r = fr + (((orig & 0x00ff0000) * polytrans) >> 5); - int g = fg + (((orig & 0x0000ff00) * polytrans) >> 5); - int b = fb + (((orig & 0x000000ff) * polytrans) >> 5); - - p[x] = 0xff000000 | (r & 0xff0000) | (g & 0xff00) | (b & 0xff); - d[x] = iz; - } - ooz += doozdx; - } - } -} diff --git a/src/mame/video/model3.c b/src/mame/video/model3.c index 3161a12cf82..df96dcebfcc 100644 --- a/src/mame/video/model3.c +++ b/src/mame/video/model3.c @@ -1,33 +1,9 @@ #include "emu.h" -#include "video/polylgcy.h" +#include "video/poly.h" #include "video/rgbutil.h" #include "includes/model3.h" - -#define pz p[0] -#define pu p[1] -#define pv p[2] - - -struct cached_texture -{ - cached_texture *next; - UINT8 width; - UINT8 height; - UINT8 format; - UINT8 alpha; - rgb_t data[1]; -}; - -struct poly_extra_data -{ - cached_texture *texture; - bitmap_ind32 *zbuffer; - UINT32 color; - UINT8 texture_param; - int polygon_transparency; - int polygon_intensity; -}; +#define ENABLE_BILINEAR 1 #define TRI_PARAM_TEXTURE_PAGE 0x1 #define TRI_PARAM_TEXTURE_MIRROR_U 0x2 @@ -35,7 +11,40 @@ struct poly_extra_data #define TRI_PARAM_TEXTURE_ENABLE 0x8 #define TRI_PARAM_ALPHA_TEST 0x10 -#define MAX_TRIANGLES 131072 +struct model3_polydata +{ + cached_texture *texture; + UINT32 color; + UINT32 texture_param; + int transparency; + int intensity; +}; + +class model3_renderer : public poly_manager +{ +public: + model3_renderer(model3_state &state, int width, int height) + : poly_manager(state.machine()), m_state(state) + { + m_fb = auto_bitmap_rgb32_alloc(state.machine(), width, height); + m_zb = auto_bitmap_ind32_alloc(state.machine(), width, height); + } + + void draw(bitmap_rgb32 &bitmap, const rectangle &cliprect); + void draw_triangle(const m3_triangle* tri); + void clear_buffers(); + void draw_scanline_solid(INT32 scanline, const extent_t &extent, const model3_polydata &extradata, int threadid); + void draw_scanline_tex(INT32 scanline, const extent_t &extent, const model3_polydata &extradata, int threadid); + void draw_scanline_contour(INT32 scanline, const extent_t &extent, const model3_polydata &extradata, int threadid); + void draw_scanline_tex_trans(INT32 scanline, const extent_t &extent, const model3_polydata &extradata, int threadid); + void draw_scanline_tex_alpha(INT32 scanline, const extent_t &extent, const model3_polydata &extradata, int threadid); + +private: + model3_state &m_state; + bitmap_rgb32 *m_fb; + bitmap_ind32 *m_zb; +}; + /*****************************************************************************/ @@ -44,14 +53,6 @@ struct poly_extra_data #define MATRIX_STACK_SIZE 256 -#ifdef UNUSED_DEFINITION -static const int num_bits[16] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 }; -#endif - - - - - #define BYTE_REVERSE32(x) (((x >> 24) & 0xff) | \ ((x >> 8) & 0xff00) | \ ((x << 8) & 0xff0000) | \ @@ -119,9 +120,8 @@ void model3_state::model3_exit() fclose(file); #endif - invalidate_texture(0, 0, 0, 6, 5); - invalidate_texture(1, 0, 0, 6, 5); - poly_free(m_poly); +// invalidate_texture(0, 0, 0, 6, 5); +// invalidate_texture(1, 0, 0, 6, 5); } void model3_state::video_start() @@ -148,11 +148,12 @@ void model3_state::video_start() 8 * 8*8 }; - m_poly = poly_alloc(machine(), 4000, sizeof(poly_extra_data), 0); - machine().add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(model3_state::model3_exit), this)); + int width = m_screen->width(); + int height = m_screen->height(); - m_screen->register_screen_bitmap(m_bitmap3d); - m_screen->register_screen_bitmap(m_zbuffer); + m_renderer = auto_alloc(machine(), model3_renderer(*this, width, height)); + + machine().add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(model3_state::model3_exit), this)); m_m3_char_ram = auto_alloc_array_clear(machine(), UINT64, 0x100000/8); m_m3_tile_ram = auto_alloc_array_clear(machine(), UINT64, 0x8000/8); @@ -170,8 +171,6 @@ void model3_state::video_start() /* 4MB Polygon RAM */ m_polygon_ram = auto_alloc_array_clear(machine(), UINT32, 0x400000/4); - m_tick = 0; - m_debug_layer_disable = 0; m_vid_reg0 = 0; m_viewport_focal_length = 300.; @@ -251,6 +250,7 @@ void model3_state::draw_layer(bitmap_rgb32 &bitmap, const rectangle &cliprect, i const pen_t *pens = m_palette->pens(); UINT32* palram = (UINT32*)&m_paletteram64[0]; + UINT16* rowscroll_ram = (UINT16*)&m_m3_char_ram[0x1ec00]; int x1 = cliprect.min_x; int y1 = cliprect.min_y; @@ -273,16 +273,30 @@ void model3_state::draw_layer(bitmap_rgb32 &bitmap, const rectangle &cliprect, i UINT32* dst = &bitmap.pix32(y); UINT16* src = &pixmap.pix16(iy & 0x1ff); - int iix = ix; + int rowscroll = BYTE_REVERSE16(rowscroll_ram[((layer * 0x200) + y) ^ NATIVE_ENDIAN_VALUE_LE_BE(3,0)]) & 0x7fff; + if (rowscroll & 0x100) + rowscroll |= ~0x1ff; - for (int x = x1; x <= x2; x++) + int iix = ix & 0x1ff; + + int rx1 = x1 - (rowscroll * 2); + int rx2 = x2 - (rowscroll * 2); + + if (rx1 < 0) + { + iix += (0 - rx1); + rx1 = 0; + } + if (rx2 > cliprect.max_x) + rx2 = cliprect.max_x; + + for (int x = rx1; x <= rx2; x++) { UINT16 p0 = src[iix & 0x1ff]; if ((palram[p0^NATIVE_ENDIAN_VALUE_LE_BE(1,0)] & NATIVE_ENDIAN_VALUE_LE_BE(0x00800000,0x00008000)) == 0) { - *dst = pens[p0]; + dst[x] = pens[p0]; } - dst++; iix++; } @@ -324,7 +338,7 @@ UINT32 model3_state::screen_update_model3(screen_device &screen, bitmap_rgb32 &b draw_layer(bitmap, cliprect, 0, m_layer_priority & 0x10, layer_scroll_x[0], layer_scroll_y[0]); // render 3D - draw_3d_layer(bitmap, cliprect); + m_renderer->draw(bitmap, cliprect); // render enabled layers with priority 1 if ((layer_data[3] & 0x80000000) && (m_layer_priority & 0x8) != 0) @@ -336,7 +350,6 @@ UINT32 model3_state::screen_update_model3(screen_device &screen, bitmap_rgb32 &b if ((layer_data[0] & 0x80000000) && (m_layer_priority & 0x1) != 0) draw_layer(bitmap, cliprect, 0, m_layer_priority & 0x10, layer_scroll_x[0], layer_scroll_y[0]); - m_real3d_display_list = 0; return 0; } @@ -620,30 +633,266 @@ cached_texture *model3_state::get_texture(int page, int texx, int texy, int texw /*****************************************************************************/ /* Real3D Graphics stuff */ +/* + Real3D Pro-1000 capabilities: + + Coordinate sets + - 4096 matrices (matrix base pointer in viewport node) + + Polygons + - 32MB max polygon memory. VROM in Model 3, the low 4MB of VROM is overlaid by Polygon RAM for runtime generated content. + + Texture + - 2 texture sheets of 2048x1024 + - Mipmaps located in the bottom right corner + - Texture size 32x32 to 1024x1024 + - Microtextures (is this featured in Model 3?) + + LODs + - 127 blend types per viewport with 4 sets of min/max angle or range (where is this in the viewport node?) + + Lighting + - Self-luminous lighting (enable and luminosity parameter in polygon structure) + - Fixed polygon shading, fixed shading weight per vertex (not found in Model 3, yet) + - Flat sun shading (lighting parameters in viewport node) needs a separate enable? + - Smooth polygon shading (lighting parameters in viewport, use vertex normals) + + Gamma table + - 256 entry 8-bit table, possibly in Polygon RAM +*/ + +/* + Real3D Memory Structures: + + Culling Nodes: + - Located in Culling RAM (0x8E000000) + - Limit of 15 child nodes (nesting), not including polygon nodes + - Color table (is this featured in Model 3?) + + 0x00: -------- -------- ------xx -------- Viewport number 0-3 + -------- -------- -------- ---xx--- Viewport priority + + 0x01: Child node pointer (inherits parameters from this node) + 0x02: Sibling node pointer + 0x03: Unknown (float) + 0x04: Sun light vector Z-component (float) + 0x05: Sun light vector X-component (float) + 0x06: Sun light vector Y-component (float) + 0x07: Sun light intensity (float) + 0x08: Far Clip plane Z + 0x09: Far Clip plane Distance + 0x0a: Near Clip plane Z + 0x0b: Near Clip plane Distance + 0x0c: Left Clip plane Z + 0x0d: Left Clip plane X + 0x0e: Top Clip plane Z + 0x0f: Top Clip plane Y + 0x10: Right Clip plane Z + 0x11: Right Clip plane X + 0x12: Bottom Clip plane Z + 0x13: Bottom Clip plane Y + + 0x14: xxxxxxxx xxxxxxxx -------- -------- Viewport height (14.2 fixed-point) + -------- -------- xxxxxxxx xxxxxxxx Viewport width (14.2 fixed-point) + + 0x15: ? + 0x16: Matrix base pointer + 0x17: LOD blend type table pointer? (seems to be 8x float per entry) + 0x18: ? + 0x19: ? + + 0x1a: xxxxxxxx xxxxxxxx -------- -------- Viewport Y coordinate (12.4 fixed-point) + -------- -------- xxxxxxxx xxxxxxxx Viewport X coordinate (12.4 fixed-point) + + 0x1b: Copy of word 0x00 + 0x1c: ? + + 0x1d: xxxxxxxx xxxxxxxx -------- -------- Spotlight Y size + -------- -------- xxxxxxxx xxxxxxxx Spotlight Y position (13.3 fixed-point?) + + 0x1e: xxxxxxxx xxxxxxxx -------- -------- Spotlight X size + -------- -------- xxxxxxxx xxxxxxxx Spotlight X position (13.3 fixed-point?) + + 0x1f: Light extent (float) + + 0x20: xxxxxxxx -------- -------- -------- ? + -------- xxxxxxxx -------- -------- ? + -------- -------- --xxx--- -------- Light RGB (RGB111?) + -------- -------- -----xxx -------- Light RGB Fog (RGB111?) + -------- -------- -------- xxxxxxxx Scroll Fog (0.8 fixed-point?) What is this??? + + 0x21: ? + 0x22: Fog Color (RGB888) + 0x23: Fog Density (float) + + 0x24: xxxxxxxx xxxxxxxx -------- -------- ? + -------- -------- xxxxxxxx -------- Sun light ambient (0.8 fixed-point) + -------- -------- -------- xxxxxxxx Scroll attenuation (0.8 fixed-point) What is this??? + + 0x25: Fog offset + 0x26: ? + 0x27: ? + 0x28: ? + 0x29: ? + 0x2a: ? + 0x2b: ? + 0x2c: ? + 0x2d: ? + 0x2e: ? + 0x2f: ? + + + Sub types: + LOD Culling Node. Up to 4 LODs. + + Articulated Part Culling Node (is this used by Model 3?) + - An Articulated Part culling node, or six degree–of–freedom node, is used to define + geometry that can move relative to the parent coordinate set to which it is attached. + Fifteen levels of coordinate set nesting (levels of articulation) are supported. + + Animation Culling Node + - Animation culling nodes are used to build a culling hierarchy for an object with different + representations, or animation frames. which can be turned on and off by the + application. Each child (culling node or polygon) added to an Animation culling node + specifies the frame for which the child is valid. + + Instance Culling Node + - Instance culling nodes define the top of a shared display list segment that can be + referenced from other parts of the scene display list. + + Instance Reference Culling Node + - An Instance Reference node is considered a leaf node; its + "child" is the shared geometry segment. An Instance Reference may be attached to + a parent node and may not have any other children, but may have siblings. + + Point Light + - A Point Light is used to create an instance of a point luminous feature. The size, + feature type, and number of sides of the point light model may be customized. + + Instance Set + - An Instance Set is a culling node which defines a set of point features. Each feature + is positioned individually. This type of culling node can be used to simulate particles. + + + + Instance Node? + + 0x00: xxxxxxxx xxxxxxxx xxxxxx-- -------- Node number/ID?, num of bits unknown + -------- -------- -------- ---x---- This node applies translation, else matrix + -------- -------- -------- ----x--- LOD enable? + -------- -------- -------- -----x-- ? + -------- -------- -------- ------x- ? + -------- -------- -------- -------x ? + + + 0x01: ? (not present on Step 1.0) + 0x02: ? (not present on Step 1.0) Scud Race has 0x00000101 + + 0x03: --x----- -------- -------- -------- ? + -------- -xxxxxxx xxxx---- -------- LOD? + -------- -------- ----xxxx xxxxxxxx Node matrix + + 0x04: Translation X coordinate + 0x05: Translation Y coordinate + 0x06: Translation Z coordinate + 0x07: Child node pointer + 0x08: Sibling node pointer + + 0x09: xxxxxxxx xxxxxxxx -------- -------- Culling or sorting related? + -------- -------- xxxxxxxx xxxxxxxx Culling or sorting related? + + + Polygon Data + + 0x00: -------- xxxxxxxx xxxxxx-- -------- Polygon ID + -------- -------- -------- -x------ 0 = Triangle, 1 = Quad + -------- -------- -------- ----x--- Vertex 3 shared from previous polygon + -------- -------- -------- -----x-- Vertex 2 shared from previous polygon + -------- -------- -------- ------x- Vertex 1 shared from previous polygon + -------- -------- -------- -------x Vertex 0 shared from previous polygon + xxxxxxxx -------- -------- x-xx---- ? + -------- -------- ------xx -------- Broken polygons in srally2 set these (a way to mark them for HW to not render?) + + 0x01: xxxxxxxx xxxxxxxx xxxxxxxx -------- Polygon normal X coordinate (2.22 fixed point) + -------- -------- -------- -x------ UV format (0 = 13.3, 1 = 16.0) + -------- -------- -------- -----x-- If set, this is the last polygon + -------- -------- -------- x-xxx-xx ? + + 0x02: xxxxxxxx xxxxxxxx xxxxxxxx -------- Polygon normal Y coordinate (2.22 fixed point) + -------- -------- -------- ------x- Texture U mirror enable + -------- -------- -------- -------x Texture V mirror enable + -------- -------- -------- xxxxxx-- ? + + 0x03: xxxxxxxx xxxxxxxx xxxxxxxx -------- Polygon normal Z coordinate (2.22 fixed point) + -------- -------- -------- --xxx--- Texture width (in 8-pixel tiles) + -------- -------- -------- -----xxx Texture height (in 8-pixel tiles) + + 0x04: xxxxxxxx xxxxxxxx xxxxxxxx -------- Color (RGB888) + -------- -------- -------- -x------ Texture page + -------- -------- -------- ---xxxxx Upper 5 bits of texture U coordinate + -------- -------- -------- x-x----- ? + + 0x05: xxxxxxxx xxxxxxxx xxxxxxxx -------- Specular color? + -------- -------- -------- x------- Low bit of texture U coordinate + -------- -------- -------- ---xxxxx Low 5 bits of texture V coordinate + -------- -------- -------- -xx----- ? + + 0x06: x------- -------- -------- -------- Texture contour enable + -----x-- -------- -------- -------- Texture enable + -------- x------- -------- -------- 1 = disable transparency? + -------- -xxxxx-- -------- -------- Polygon transparency (0 = fully transparent) + -------- -------x -------- -------- 1 = disable lighting + -------- -------- xxxxx--- -------- Polygon luminosity + -------- -------- ------xx x------- Texture format + -------- -------- -------- -------x Alpha enable? + -xxxx-xx ------x- -----x-- -xxxxxx- ? + + + Vertex entry + + 0x00: xxxxxxxx xxxxxxxx xxxxxxxx -------- Vertex X coordinate (17.7 fixed-point in Step 1.0, 13.11 otherwise) + -------- -------- -------- xxxxxxxx Vertex normal X (offset from polygon normal) + + 0x01: xxxxxxxx xxxxxxxx xxxxxxxx -------- Vertex Y coordinate + -------- -------- -------- xxxxxxxx Vertex normal Y + + 0x02: xxxxxxxx xxxxxxxx xxxxxxxx -------- Vertex Z coordinate + -------- -------- -------- xxxxxxxx Vertex normal Z + + 0x03: xxxxxxxx xxxxxxxx -------- -------- Vertex U coordinate + -------- -------- xxxxxxxx xxxxxxxx Vertex V coordinate + +*/ + + WRITE64_MEMBER(model3_state::real3d_display_list_w) { - if(ACCESSING_BITS_32_63) { + if (ACCESSING_BITS_32_63) + { m_display_list_ram[offset*2] = BYTE_REVERSE32((UINT32)(data >> 32)); } - if(ACCESSING_BITS_0_31) { + if (ACCESSING_BITS_0_31) + { m_display_list_ram[(offset*2)+1] = BYTE_REVERSE32((UINT32)(data)); } } WRITE64_MEMBER(model3_state::real3d_polygon_ram_w) { - if(ACCESSING_BITS_32_63) { + if (ACCESSING_BITS_32_63) + { m_polygon_ram[offset*2] = BYTE_REVERSE32((UINT32)(data >> 32)); } - if(ACCESSING_BITS_0_31) { + if (ACCESSING_BITS_0_31) + { m_polygon_ram[(offset*2)+1] = BYTE_REVERSE32((UINT32)(data)); } } static const UINT8 texture_decode[64] = { - 0, 1, 4, 5, 8, 9, 12, 13, - 2, 3, 6, 7, 10, 11, 14, 15, + 0, 1, 4, 5, 8, 9, 12, 13, + 2, 3, 6, 7, 10, 11, 14, 15, 16, 17, 20, 21, 24, 25, 28, 29, 18, 19, 22, 23, 26, 27, 30, 31, 32, 33, 36, 37, 40, 41, 44, 45, @@ -753,8 +1002,7 @@ void model3_state::real3d_display_list_end() } m_texture_fifo_pos = 0; - m_zbuffer.fill(0); - m_bitmap3d.fill(0); + m_renderer->clear_buffers(); real3d_traverse_display_list(); } @@ -765,12 +1013,11 @@ void model3_state::real3d_display_list1_dma(UINT32 src, UINT32 dst, int length, int d = (dst & 0xffffff) / 4; for (int i = 0; i < length; i += 4) { - UINT32 w; - if (byteswap) { - w = BYTE_REVERSE32(space.read_dword(src)); - } else { - w = space.read_dword(src); - } + UINT32 w = space.read_dword(src); + + if (byteswap) + w = BYTE_REVERSE32(w); + m_display_list_ram[d++] = w; src += 4; } @@ -782,12 +1029,11 @@ void model3_state::real3d_display_list2_dma(UINT32 src, UINT32 dst, int length, int d = (dst & 0xffffff) / 4; for (int i = 0; i < length; i += 4) { - UINT32 w; - if (byteswap) { - w = BYTE_REVERSE32(space.read_dword(src)); - } else { - w = space.read_dword(src); - } + UINT32 w = space.read_dword(src); + + if (byteswap) + w = BYTE_REVERSE32(w); + m_culling_ram[d++] = w; src += 4; } @@ -800,15 +1046,15 @@ void model3_state::real3d_vrom_texture_dma(UINT32 src, UINT32 dst, int length, i { for (int i=0; i < length; i+=12) { - UINT32 address, header; + UINT32 address = space.read_dword(src+i+0); + UINT32 header = space.read_dword(src+i+4); - if (byteswap) { - address = BYTE_REVERSE32(space.read_dword((src+i+0))); - header = BYTE_REVERSE32(space.read_dword((src+i+4))); - } else { - address = space.read_dword((src+i+0)); - header = space.read_dword((src+i+4)); + if (byteswap) + { + address = BYTE_REVERSE32(address); + header = BYTE_REVERSE32(header); } + real3d_upload_texture(header, (UINT32*)&m_vrom[address]); } } @@ -819,12 +1065,11 @@ void model3_state::real3d_texture_fifo_dma(UINT32 src, int length, int byteswap) address_space &space = m_maincpu->space(AS_PROGRAM); for (int i = 0; i < length; i += 4) { - UINT32 w; - if (byteswap) { - w = BYTE_REVERSE32(space.read_dword(src)); - } else { - w = space.read_dword(src); - } + UINT32 w = space.read_dword(src); + + if (byteswap) + w = BYTE_REVERSE32(w); + m_texture_fifo[m_texture_fifo_pos] = w; m_texture_fifo_pos++; src += 4; @@ -837,12 +1082,11 @@ void model3_state::real3d_polygon_ram_dma(UINT32 src, UINT32 dst, int length, in int d = (dst & 0xffffff) / 4; for (int i = 0; i < length; i += 4) { - UINT32 w; - if (byteswap) { - w = BYTE_REVERSE32(space.read_dword(src)); - } else { - w = space.read_dword(src); - } + UINT32 w = space.read_dword(src); + + if (byteswap) + w = BYTE_REVERSE32(w); + m_polygon_ram[d++] = w; src += 4; } @@ -857,13 +1101,6 @@ WRITE64_MEMBER(model3_state::real3d_cmd_w) /*****************************************************************************/ /* matrix and vector operations */ -#ifdef UNUSED_FUNCTION -INLINE float dot_product(VECTOR a, VECTOR b) -{ - return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]) + (a[3] * b[3]); -} -#endif - INLINE float dot_product3(VECTOR3 a, VECTOR3 b) { return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]); @@ -959,29 +1196,27 @@ void model3_state::translate_matrix_stack(float x, float y, float z) /*****************************************************************************/ /* transformation and rasterizing */ -#include "m3raster.inc" - -INLINE int is_point_inside(float x, float y, float z, PLANE cp) +INLINE bool is_point_inside(float x, float y, float z, m3_plane cp) { float s = (x * cp.x) + (y * cp.y) + (z * cp.z) + cp.d; if (s >= 0.0f) - return 1; + return true; else - return 0; + return false; } -INLINE float line_plane_intersection(const poly_vertex *v1, const poly_vertex *v2, PLANE cp) +INLINE float line_plane_intersection(const m3_clip_vertex *v1, const m3_clip_vertex *v2, m3_plane cp) { float x = v1->x - v2->x; float y = v1->y - v2->y; - float z = v1->pz - v2->pz; - float t = ((cp.x * v1->x) + (cp.y * v1->y) + (cp.z * v1->pz)) / ((cp.x * x) + (cp.y * y) + (cp.z * z)); + float z = v1->z - v2->z; + float t = ((cp.x * v1->x) + (cp.y * v1->y) + (cp.z * v1->z)) / ((cp.x * x) + (cp.y * y) + (cp.z * z)); return t; } -static int clip_polygon(const poly_vertex *v, int num_vertices, PLANE cp, poly_vertex *vout) +static int clip_polygon(const m3_clip_vertex *v, int num_vertices, m3_plane cp, m3_clip_vertex *vout) { - poly_vertex clipv[10]; + m3_clip_vertex clipv[10]; int clip_verts = 0; float t; int i; @@ -990,8 +1225,8 @@ static int clip_polygon(const poly_vertex *v, int num_vertices, PLANE cp, poly_v for (i=0; i < num_vertices; i++) { - int v1_in = is_point_inside(v[i].x, v[i].y, v[i].pz, cp); - int v2_in = is_point_inside(v[previ].x, v[previ].y, v[previ].pz, cp); + bool v1_in = is_point_inside(v[i].x, v[i].y, v[i].z, cp); + bool v2_in = is_point_inside(v[previ].x, v[previ].y, v[previ].z, cp); if (v1_in && v2_in) /* edge is completely inside the volume */ { @@ -1004,9 +1239,10 @@ static int clip_polygon(const poly_vertex *v, int num_vertices, PLANE cp, poly_v t = line_plane_intersection(&v[i], &v[previ], cp); clipv[clip_verts].x = v[i].x + ((v[previ].x - v[i].x) * t); clipv[clip_verts].y = v[i].y + ((v[previ].y - v[i].y) * t); - clipv[clip_verts].pz = v[i].pz + ((v[previ].pz - v[i].pz) * t); - clipv[clip_verts].pu = v[i].pu + ((v[previ].pu - v[i].pu) * t); - clipv[clip_verts].pv = v[i].pv + ((v[previ].pv - v[i].pv) * t); + clipv[clip_verts].z = v[i].z + ((v[previ].z - v[i].z) * t); + clipv[clip_verts].u = v[i].u + ((v[previ].u - v[i].u) * t); + clipv[clip_verts].v = v[i].v + ((v[previ].v - v[i].v) * t); + clipv[clip_verts].i = v[i].i + ((v[previ].i - v[i].i) * t); ++clip_verts; } else if (v1_in && !v2_in) /* edge is leaving the volume */ @@ -1015,9 +1251,10 @@ static int clip_polygon(const poly_vertex *v, int num_vertices, PLANE cp, poly_v t = line_plane_intersection(&v[i], &v[previ], cp); clipv[clip_verts].x = v[i].x + ((v[previ].x - v[i].x) * t); clipv[clip_verts].y = v[i].y + ((v[previ].y - v[i].y) * t); - clipv[clip_verts].pz = v[i].pz + ((v[previ].pz - v[i].pz) * t); - clipv[clip_verts].pu = v[i].pu + ((v[previ].pu - v[i].pu) * t); - clipv[clip_verts].pv = v[i].pv + ((v[previ].pv - v[i].pv) * t); + clipv[clip_verts].z = v[i].z + ((v[previ].z - v[i].z) * t); + clipv[clip_verts].u = v[i].u + ((v[previ].u - v[i].u) * t); + clipv[clip_verts].v = v[i].v + ((v[previ].v - v[i].v) * t); + clipv[clip_verts].i = v[i].i + ((v[previ].i - v[i].i) * t); ++clip_verts; /* insert the existing vertex */ @@ -1031,70 +1268,29 @@ static int clip_polygon(const poly_vertex *v, int num_vertices, PLANE cp, poly_v return clip_verts; } -void model3_state::render_one(TRIANGLE *tri) -{ - poly_extra_data *extra = (poly_extra_data *)poly_get_extra_data(m_poly); - poly_draw_scanline_func callback = NULL; - - tri->v[0].pz = 1.0f / tri->v[0].pz; - tri->v[1].pz = 1.0f / tri->v[1].pz; - tri->v[2].pz = 1.0f / tri->v[2].pz; - - extra->zbuffer = &m_zbuffer; - if (tri->param & TRI_PARAM_TEXTURE_ENABLE) - { - tri->v[0].pu = tri->v[0].pu * tri->v[0].pz * 256.0f; - tri->v[0].pv = tri->v[0].pv * tri->v[0].pz * 256.0f; - tri->v[1].pu = tri->v[1].pu * tri->v[1].pz * 256.0f; - tri->v[1].pv = tri->v[1].pv * tri->v[1].pz * 256.0f; - tri->v[2].pu = tri->v[2].pu * tri->v[2].pz * 256.0f; - tri->v[2].pv = tri->v[2].pv * tri->v[2].pz * 256.0f; - - extra->texture = get_texture((tri->param & TRI_PARAM_TEXTURE_PAGE) ? 1 : 0, tri->texture_x, tri->texture_y, tri->texture_width, tri->texture_height, tri->texture_format); - extra->texture_param = tri->param; - extra->polygon_transparency = tri->transparency; - extra->polygon_intensity = tri->intensity; - - if (tri->param & TRI_PARAM_ALPHA_TEST) - callback = draw_scanline_alpha_test; - else if (extra->texture->alpha == 0xff) - callback = (tri->transparency >= 32) ? draw_scanline_normal : draw_scanline_trans; - else - callback = draw_scanline_alpha; - poly_render_triangle(m_poly, &m_bitmap3d, m_clip3d, callback, 3, &tri->v[0], &tri->v[1], &tri->v[2]); - } - else - { - extra->polygon_transparency = tri->transparency; - extra->polygon_intensity = tri->intensity; - extra->color = tri->color; - - poly_render_triangle(m_poly, &m_bitmap3d, m_clip3d, draw_scanline_color, 1, &tri->v[0], &tri->v[1], &tri->v[2]); - } -} - void model3_state::draw_model(UINT32 addr) { + // Polygon RAM is mapped to the low 4MB of VROM UINT32 *model = (addr >= 0x100000) ? &m_vrom[addr] : &m_polygon_ram[addr]; + UINT32 header[7]; int index = 0; int last_polygon = FALSE, first_polygon = TRUE, back_face = FALSE; int num_vertices; int i, v, vi; float fixed_point_fraction; - poly_vertex vertex[4]; - poly_vertex prev_vertex[4]; - poly_vertex clip_vert[10]; + m3_vertex vertex[4]; + m3_vertex prev_vertex[4]; + m3_clip_vertex clip_vert[10]; MATRIX transform_matrix; float center_x, center_y; - if(m_step < 0x15) { /* position coordinates are 17.15 fixed-point in Step 1.0 */ - fixed_point_fraction = 1.0f / 32768.0f; - } else { /* 13.19 fixed-point in other Steps */ - fixed_point_fraction = 1.0f / 524288.0f; - } - + if (m_step < 0x15) // position coordinates are 17.7 fixed-point in Step 1.0 + fixed_point_fraction = 1.0f / 128.0f; + else // 13.11 fixed-point in other Steps + fixed_point_fraction = 1.0f / 2048.0f; + get_top_matrix(&transform_matrix); /* current viewport center coordinates on screen */ @@ -1110,51 +1306,10 @@ void model3_state::draw_model(UINT32 addr) VECTOR3 normal; VECTOR3 sn; VECTOR p[4]; - TRIANGLE tri; + m3_triangle tri; float dot; - int intensity; int polygon_transparency; - // - // Header bits: - // - // 0:00FFFC00 - polygon ID - // 0:00000300 - ???? - // 0:00000040 - if set, indicates a quad, else it's a triangle - // 0:00000008 - inherit vertex 3 from previous polygon - // 0:00000004 - inherit vertex 2 from previous polygon - // 0:00000002 - inherit vertex 1 from previous polygon - // 0:00000001 - inherit vertex 0 from previous polygon - // - // 1:FFFFFF00 - polygon normal X coordinate, 2.22 - // 1:00000040 - if set, U/V is as-is, else divide U/V by 8 - // 1:00000004 - if set, indicates last polygon in model - // - // 2:FFFFFF00 - polygon normal Y coordinate, 2.22 - // 2:00000002 - if set, mirror texture in U - // 2:00000001 - if set, mirror texture in V - // - // 3:FFFFFF00 - polygon normal Z coordinate, 2.22 - // 3:00000038 - texture width, in tiles - // 3:00000007 - texture height, in tiles - // - // 4:FFFFFF00 - RGB lighting color - // 4:00000040 - texture page - // 4:0000001F - upper 5 bits of texture X coordinate - // - // 5:00000080 - low bit of texture X coordinate - // 5:0000001F - low 5 bits of texture Y coordinate - // - // 6:80000000 - if set, enable alpha test - // 6:04000000 - if set, textures enabled - // 6:00800000 - if set, force transparency off - // 6:007C0000 - 5-bit transparency value (0 is transparent, 0x1F is nearly opaque) - // 6:00010000 - if set, disable lighting - // 6:0000F800 - 5-bit additional color control - // 6:00000380 - 3-bit texture format - // 6:00000001 - alpha enable? - // - for (i = 0; i < 7; i++) header[i] = model[index++]; @@ -1168,6 +1323,9 @@ void model3_state::draw_model(UINT32 addr) if (header[1] & 0x4) last_polygon = TRUE; + if ((header[0] & 0x300) == 0x300) // TODO: broken polygons in srally2 have these bits set + return; + num_vertices = (header[0] & 0x40) ? 4 : 3; /* texture coordinates are 16.0 or 13.3 fixed-point */ @@ -1187,22 +1345,28 @@ void model3_state::draw_model(UINT32 addr) /* load new vertices */ for ( ; vi < num_vertices; vi++) { - if ((model[index+0] & 0xf0000000) == 0x70000000 || - (model[index+1] & 0xf0000000) == 0x70000000 || - (model[index+2] & 0xf0000000) == 0x70000000) - return; + UINT32 xw = model[index++]; + UINT32 yw = model[index++]; + UINT32 zw = model[index++]; - vertex[vi].x = (float)((INT32)model[index++]) * fixed_point_fraction; - vertex[vi].y = (float)((INT32)model[index++]) * fixed_point_fraction; - vertex[vi].pz = (float)((INT32)model[index++]) * fixed_point_fraction; - vertex[vi].pu = (UINT16)(model[index] >> 16); - vertex[vi].pv = (UINT16)(model[index++]); + vertex[vi].x = (float)((INT32)(xw) >> 8) * fixed_point_fraction; + vertex[vi].y = (float)((INT32)(yw) >> 8) * fixed_point_fraction; + vertex[vi].z = (float)((INT32)(zw) >> 8) * fixed_point_fraction; + vertex[vi].u = (UINT16)(model[index] >> 16); + vertex[vi].v = (UINT16)(model[index++]); +// vertex[vi].nx = normal[0] + ((float)((INT8)(xw)) / 127.0f); +// vertex[vi].ny = normal[1] + ((float)((INT8)(yw)) / 127.0f); +// vertex[vi].nz = normal[2] + ((float)((INT8)(zw)) / 127.0f); + + vertex[vi].nx = ((float)((INT8)(xw)) / 127.0f); + vertex[vi].ny = ((float)((INT8)(yw)) / 127.0f); + vertex[vi].nz = ((float)((INT8)(zw)) / 127.0f); } /* Copy current vertices as previous vertices */ - memcpy(prev_vertex, vertex, sizeof(poly_vertex) * 4); + memcpy(prev_vertex, vertex, sizeof(m3_vertex) * 4); - color = (((header[4] >> 27) & 0x1f) << 10) | (((header[4] >> 19) & 0x1f) << 5) | ((header[4] >> 11) & 0x1f); + color = (header[4] >> 8) & 0xffffff; polygon_transparency = (header[6] & 0x800000) ? 32 : ((header[6] >> 18) & 0x1f); /* transform polygon normal to view-space */ @@ -1220,26 +1384,64 @@ void model3_state::draw_model(UINT32 addr) sn[1] *= m_coordinate_system[1][2]; sn[2] *= m_coordinate_system[2][0]; - /* TODO: depth bias */ - /* transform vertices */ + // TODO: depth bias + // transform and light vertices for (i = 0; i < num_vertices; i++) { VECTOR vect; vect[0] = vertex[i].x; vect[1] = vertex[i].y; - vect[2] = vertex[i].pz; + vect[2] = vertex[i].z; vect[3] = 1.0f; - /* transform to world-space */ + // transform to world-space matrix_multiply_vector(transform_matrix, vect, &p[i]); - /* apply coordinate system */ + // apply coordinate system clip_vert[i].x = p[i][0] * m_coordinate_system[0][1]; clip_vert[i].y = p[i][1] * m_coordinate_system[1][2]; - clip_vert[i].pz = p[i][2] * m_coordinate_system[2][0]; - clip_vert[i].pu = vertex[i].pu * texture_coord_scale; - clip_vert[i].pv = vertex[i].pv * texture_coord_scale; + clip_vert[i].z = p[i][2] * m_coordinate_system[2][0]; + clip_vert[i].u = vertex[i].u * texture_coord_scale; + clip_vert[i].v = vertex[i].v * texture_coord_scale; + + // transform vertex normal + VECTOR3 n; + n[0] = (vertex[i].nx * transform_matrix[0][0]) + + (vertex[i].ny * transform_matrix[1][0]) + + (vertex[i].nz * transform_matrix[2][0]); + n[0] *= m_coordinate_system[0][1]; + n[1] = (vertex[i].nx * transform_matrix[0][1]) + + (vertex[i].ny * transform_matrix[1][1]) + + (vertex[i].nz * transform_matrix[2][1]); + n[1] *= m_coordinate_system[1][2]; + n[2] = (vertex[i].nx * transform_matrix[0][2]) + + (vertex[i].ny * transform_matrix[1][2]) + + (vertex[i].nz * transform_matrix[2][2]); + n[2] *= m_coordinate_system[2][0]; + + // lighting + float intensity; + if ((header[6] & 0x10000) == 0) + { + dot = dot_product3(n, m_parallel_light); + intensity = ((dot * m_parallel_light_intensity) + m_ambient_light_intensity) * 255.0f; + if (intensity > 255.0f) + { + intensity = 255.0f; + } + if (intensity < 0.0f) + { + intensity = 0.0f; + } + } + else + { + // apply luminosity + intensity = ((float)((header[6] >> 11) & 0x1f) / 31.0f) * 255.0f; + } + + clip_vert[i].i = intensity; } /* clip against view frustum */ @@ -1251,7 +1453,7 @@ void model3_state::draw_model(UINT32 addr) /* backface culling */ if( (header[6] & 0x800000) && (!(header[1] & 0x0010)) ) { - if(sn[0]*clip_vert[0].x + sn[1]*clip_vert[0].y + sn[2]*clip_vert[0].pz >0) + if(sn[0]*clip_vert[0].x + sn[1]*clip_vert[0].y + sn[2]*clip_vert[0].z >0) back_face = 1; else back_face = 0; @@ -1259,47 +1461,48 @@ void model3_state::draw_model(UINT32 addr) else back_face = 0; //no culling for transparent or two-sided polygons - if(!back_face) { + if (!back_face) + { /* homogeneous Z-divide, screen-space transformation */ - for(i=0; i < num_vertices; i++) { - float ooz = 1.0f / clip_vert[i].pz; + for(i=0; i < num_vertices; i++) + { + float ooz = 1.0f / clip_vert[i].z; clip_vert[i].x = ((clip_vert[i].x * ooz) * m_viewport_focal_length) + center_x; clip_vert[i].y = ((clip_vert[i].y * ooz) * m_viewport_focal_length) + center_y; + clip_vert[i].u *= ooz; + clip_vert[i].v *= ooz; } - // lighting - if ((header[6] & 0x10000) == 0) + + cached_texture* texture; + + if (header[6] & 0x4000000) { - dot = dot_product3(sn, m_parallel_light); - intensity = ((dot * m_parallel_light_intensity) + m_ambient_light_intensity) * 256.0f; - if (intensity > 256) - { - intensity = 256; - } - if (intensity < 0) - { - intensity = 0; - } + int tex_x = ((header[4] & 0x1f) << 1) | ((header[5] >> 7) & 0x1); + int tex_y = (header[5] & 0x1f); + int tex_width = ((header[3] >> 3) & 0x7); + int tex_height = (header[3] & 0x7); + int tex_format = (header[6] >> 7) & 0x7; + + if (tex_width >= 6 || tex_height >= 6) // srally2 poly ram has degenerate polys with 2k tex size (cpu bug or intended?) + return; + + texture = get_texture((header[4] & 0x40) ? 1 : 0, tex_x, tex_y, tex_width, tex_height, tex_format); } else { - // apply luminosity - intensity = 256; + texture = NULL; } for (i=2; i < num_vertices; i++) { - memcpy(&tri.v[0], &clip_vert[0], sizeof(poly_vertex)); - memcpy(&tri.v[1], &clip_vert[i-1], sizeof(poly_vertex)); - memcpy(&tri.v[2], &clip_vert[i], sizeof(poly_vertex)); - tri.texture_x = ((header[4] & 0x1f) << 1) | ((header[5] >> 7) & 0x1); - tri.texture_y = (header[5] & 0x1f); - tri.texture_width = ((header[3] >> 3) & 0x7); - tri.texture_height = (header[3] & 0x7); - tri.texture_format = (header[6] >> 7) & 0x7; - tri.transparency = polygon_transparency; - tri.intensity = intensity; - tri.color = color; + memcpy(&tri.v[0], &clip_vert[0], sizeof(m3_clip_vertex)); + memcpy(&tri.v[1], &clip_vert[i-1], sizeof(m3_clip_vertex)); + memcpy(&tri.v[2], &clip_vert[i], sizeof(m3_clip_vertex)); + + tri.texture = texture; + tri.transparency = polygon_transparency; + tri.color = color >> 8; tri.param = 0; tri.param |= (header[4] & 0x40) ? TRI_PARAM_TEXTURE_PAGE : 0; @@ -1308,7 +1511,7 @@ void model3_state::draw_model(UINT32 addr) tri.param |= (header[2] & 0x1) ? TRI_PARAM_TEXTURE_MIRROR_V : 0; tri.param |= (header[6] & 0x80000000) ? TRI_PARAM_ALPHA_TEST : 0; - render_one(&tri); + m_renderer->draw_triangle(&tri); } } } @@ -1521,20 +1724,20 @@ void model3_state::real3d_traverse_display_list() { init_matrix_stack(); + m_list_depth = 0; + for (int pri = 0; pri < 4; pri++) draw_viewport(pri, 0x800000); - - poly_wait(m_poly, "real3d_traverse_display_list"); } -void model3_state::draw_3d_layer(bitmap_rgb32 &bitmap, const rectangle &cliprect) +void model3_renderer::draw(bitmap_rgb32 &bitmap, const rectangle &cliprect) { int i, j; for (j = cliprect.min_y; j <= cliprect.max_y; ++j) { UINT32 *dst = &bitmap.pix32(j); - UINT32 *src = &m_bitmap3d.pix32(j); + UINT32 *src = &m_fb->pix32(j); for (i = cliprect.min_x; i <= cliprect.max_x; ++i) { @@ -1544,4 +1747,390 @@ void model3_state::draw_3d_layer(bitmap_rgb32 &bitmap, const rectangle &cliprect } } } +} + +void model3_renderer::clear_buffers() +{ + rectangle cliprect; + cliprect.min_x = 0; + cliprect.min_y = 0; + cliprect.max_x = 495; + cliprect.max_y = 383; + + m_fb->fill(0x00000000, cliprect); + + float zvalue = 10000000000.0f; + m_zb->fill(*(int*)&zvalue, cliprect); +} + +void model3_renderer::draw_triangle(const m3_triangle *tri) +{ + rectangle cliprect; + cliprect.min_x = 0; + cliprect.min_y = 0; + cliprect.max_x = 495; + cliprect.max_y = 383; + + vertex_t v[3]; + + if (tri->param & TRI_PARAM_TEXTURE_ENABLE) + { + for (int i=0; i < 3; i++) + { + v[i].x = tri->v[i].x; + v[i].y = tri->v[i].y; + v[i].p[0] = tri->v[i].z; + v[i].p[1] = 1.0f / tri->v[i].z; + v[i].p[2] = tri->v[i].u * 256.0f; // 8 bits of subtexel precision for bilinear filtering + v[i].p[3] = tri->v[i].v * 256.0f; + v[i].p[4] = tri->v[i].i; + } + + model3_polydata &extra = object_data_alloc(); + extra.texture = tri->texture; + extra.transparency = tri->transparency; + extra.intensity = tri->intensity; + extra.texture_param = tri->param; + + render_delegate rd; + if (tri->param & TRI_PARAM_ALPHA_TEST) + { + rd = render_delegate(FUNC(model3_renderer::draw_scanline_contour), this); + } + else if (extra.texture->alpha == 0xff) + { + if (tri->transparency >= 32) + rd = render_delegate(FUNC(model3_renderer::draw_scanline_tex), this); + else + rd = render_delegate(FUNC(model3_renderer::draw_scanline_tex_trans), this); + } + else + { + rd = render_delegate(FUNC(model3_renderer::draw_scanline_tex_alpha), this); + } + + render_triangle(cliprect, rd, 5, v[0], v[1], v[2]); + } + else + { + for (int i=0; i < 3; i++) + { + v[i].x = tri->v[i].x; + v[i].y = tri->v[i].y; + v[i].p[0] = tri->v[i].z; + v[i].p[1] = tri->v[i].i; + } + + model3_polydata &extra = object_data_alloc(); + + extra.intensity = tri->intensity; + extra.color = tri->color; + + render_triangle(cliprect, render_delegate(FUNC(model3_renderer::draw_scanline_solid), this), 2, v[0], v[1], v[2]); + } +} + +void model3_renderer::draw_scanline_solid(INT32 scanline, const extent_t &extent, const model3_polydata &polydata, int threadid) +{ + UINT32 *fb = &m_fb->pix32(scanline); + float *zb = (float*)&m_zb->pix32(scanline); + + float z = extent.param[0].start; + float dz = extent.param[0].dpdx; + + float in = extent.param[1].start; + float inz = extent.param[1].dpdx; + + int r = polydata.color & 0xff0000; + int g = polydata.color & 0xff00; + int b = polydata.color & 0xff; + + int srctrans = polydata.transparency; + int desttrans = 32 - polydata.transparency; + + for (int x = extent.startx; x < extent.stopx; x++) + { + if (z < zb[x]) + { + int ii = (int)(in); + + r = (r * ii) >> 8; + g = (g * ii) >> 8; + b = (b * ii) >> 8; + + if (srctrans != 0x1f) + { + UINT32 orig = fb[x]; + r = (r * srctrans) >> 5; + g = (g * srctrans) >> 5; + b = (b * srctrans) >> 5; + r += ((orig & 0x00ff0000) * desttrans) >> 5; + g += ((orig & 0x0000ff00) * desttrans) >> 5; + b += ((orig & 0x000000ff) * desttrans) >> 5; + } + + fb[x] = 0xff000000 | (r & 0xff0000) | (g & 0xff00) | (b & 0xff); + zb[x] = z; + } + + in += inz; + z += dz; + } +} + +#define TEX_FETCH_NOFILTER() \ +do { \ + float intz = 1.0f / ooz; \ + UINT32 u = uoz * intz; \ + UINT32 v = voz * intz; \ + UINT32 u1 = (u >> 8) & umask; \ + UINT32 v1 = (v >> 8) & vmask; \ + texel = texture->data[(v1 << width) + u1]; \ +} while(0); + +#define TEX_FETCH_BILINEAR() \ +do { \ + float intz = 1.0f / ooz; \ + UINT32 u = uoz * intz; \ + UINT32 v = voz * intz; \ + UINT32 u1 = (u >> 8) & umask; \ + UINT32 v1 = (v >> 8) & vmask; \ + UINT32 u2 = (u1 + 1) & umask; \ + UINT32 v2 = (v1 + 1) & vmask; \ + UINT32 pix00 = texture->data[(v1 << width) + u1]; \ + UINT32 pix01 = texture->data[(v1 << width) + u2]; \ + UINT32 pix10 = texture->data[(v2 << width) + u1]; \ + UINT32 pix11 = texture->data[(v2 << width) + u2]; \ + texel = rgba_bilinear_filter(pix00, pix01, pix10, pix11, u, v); \ +} while(0); + +#if ENABLE_BILINEAR +#define TEX_FETCH() TEX_FETCH_BILINEAR() +#else +#define TEX_FETCH() TEX_FETCH_NOFILTER() +#endif + +void model3_renderer::draw_scanline_tex(INT32 scanline, const extent_t &extent, const model3_polydata &polydata, int threadid) +{ + UINT32 *fb = &m_fb->pix32(scanline); + float *zb = (float*)&m_zb->pix32(scanline); + const cached_texture *texture = polydata.texture; + + float z = extent.param[0].start; + float dz = extent.param[0].dpdx; + float ooz = extent.param[1].start; + float dooz = extent.param[1].dpdx; + float uoz = extent.param[2].start; + float duoz = extent.param[2].dpdx; + float voz = extent.param[3].start; + float dvoz = extent.param[3].dpdx; + float in = extent.param[4].start; + float inz = extent.param[4].dpdx; + + UINT32 umask = (((polydata.texture_param & TRI_PARAM_TEXTURE_MIRROR_U) ? 64 : 32) << texture->width) - 1; + UINT32 vmask = (((polydata.texture_param & TRI_PARAM_TEXTURE_MIRROR_V) ? 64 : 32) << texture->height) - 1; + UINT32 width = 6 + texture->width; + + for (int x = extent.startx; x < extent.stopx; x++) + { + if (z < zb[x]) + { + UINT32 texel; + TEX_FETCH(); + + int ii = in; + + UINT32 r = ((texel & 0xff0000) * ii) >> 8; + UINT32 g = ((texel & 0xff00) * ii) >> 8; + UINT32 b = ((texel & 0xff) * ii) >> 8; + + fb[x] = 0xff000000 | (r & 0xff0000) | (g & 0xff00) | (b & 0xff); + zb[x] = z; + } + + ooz += dooz; + uoz += duoz; + voz += dvoz; + in += inz; + z += dz; + } +} + +void model3_renderer::draw_scanline_contour(INT32 scanline, const extent_t &extent, const model3_polydata &polydata, int threadid) +{ + UINT32 *fb = &m_fb->pix32(scanline); + float *zb = (float*)&m_zb->pix32(scanline); + const cached_texture *texture = polydata.texture; + + float z = extent.param[0].start; + float dz = extent.param[0].dpdx; + float ooz = extent.param[1].start; + float dooz = extent.param[1].dpdx; + float uoz = extent.param[2].start; + float duoz = extent.param[2].dpdx; + float voz = extent.param[3].start; + float dvoz = extent.param[3].dpdx; + float in = extent.param[4].start; + float inz = extent.param[4].dpdx; + + UINT32 umask = (((polydata.texture_param & TRI_PARAM_TEXTURE_MIRROR_U) ? 64 : 32) << texture->width) - 1; + UINT32 vmask = (((polydata.texture_param & TRI_PARAM_TEXTURE_MIRROR_V) ? 64 : 32) << texture->height) - 1; + UINT32 width = 6 + texture->width; + + for (int x = extent.startx; x < extent.stopx; x++) + { + if (z < zb[x]) + { + UINT32 texel; + TEX_FETCH(); + + UINT32 fa = texel >> 24; + if (fa >= 0xf8) + { + UINT32 r = ((texel & 0x00ff0000) * fa) >> 8; + UINT32 g = ((texel & 0x0000ff00) * fa) >> 8; + UINT32 b = ((texel & 0x000000ff) * fa) >> 8; + + UINT32 orig = fb[x]; + + int minalpha = 255 - fa; + + r += ((orig & 0x00ff0000) * minalpha) >> 8; + g += ((orig & 0x0000ff00) * minalpha) >> 8; + b += ((orig & 0x000000ff) * minalpha) >> 8; + + fb[x] = 0xff000000 | (r & 0xff0000) | (g & 0xff00) | (b & 0xff); + zb[x] = z; + } + } + + ooz += dooz; + uoz += duoz; + voz += dvoz; + in += inz; + z += dz; + } +} + +void model3_renderer::draw_scanline_tex_trans(INT32 scanline, const extent_t &extent, const model3_polydata &polydata, int threadid) +{ + UINT32 *fb = &m_fb->pix32(scanline); + float *zb = (float*)&m_zb->pix32(scanline); + const cached_texture *texture = polydata.texture; + + float z = extent.param[0].start; + float dz = extent.param[0].dpdx; + float ooz = extent.param[1].start; + float dooz = extent.param[1].dpdx; + float uoz = extent.param[2].start; + float duoz = extent.param[2].dpdx; + float voz = extent.param[3].start; + float dvoz = extent.param[3].dpdx; + float in = extent.param[4].start; + float inz = extent.param[4].dpdx; + + int srctrans = polydata.transparency; + int desttrans = 32 - polydata.transparency; + + UINT32 umask = (((polydata.texture_param & TRI_PARAM_TEXTURE_MIRROR_U) ? 64 : 32) << texture->width) - 1; + UINT32 vmask = (((polydata.texture_param & TRI_PARAM_TEXTURE_MIRROR_V) ? 64 : 32) << texture->height) - 1; + UINT32 width = 6 + texture->width; + + for (int x = extent.startx; x < extent.stopx; x++) + { + if (z < zb[x]) + { + UINT32 texel; + TEX_FETCH(); + + int ii = (int)in; + + UINT32 r = ((texel & 0x00ff0000) * ii) >> 8; + UINT32 g = ((texel & 0x0000ff00) * ii) >> 8; + UINT32 b = ((texel & 0x000000ff) * ii) >> 8; + + r = (r * srctrans) >> 5; + g = (g * srctrans) >> 5; + b = (b * srctrans) >> 5; + + UINT32 orig = fb[x]; + + r += ((orig & 0x00ff0000) * desttrans) >> 5; + g += ((orig & 0x0000ff00) * desttrans) >> 5; + b += ((orig & 0x000000ff) * desttrans) >> 5; + + fb[x] = 0xff000000 | (r & 0xff0000) | (g & 0xff00) | (b & 0xff); + zb[x] = z; + } + + ooz += dooz; + uoz += duoz; + voz += dvoz; + in += inz; + z += dz; + } +} + +void model3_renderer::draw_scanline_tex_alpha(INT32 scanline, const extent_t &extent, const model3_polydata &polydata, int threadid) +{ + UINT32 *fb = &m_fb->pix32(scanline); + float *zb = (float*)&m_zb->pix32(scanline); + const cached_texture *texture = polydata.texture; + + float z = extent.param[0].start; + float dz = extent.param[0].dpdx; + float ooz = extent.param[1].start; + float dooz = extent.param[1].dpdx; + float uoz = extent.param[2].start; + float duoz = extent.param[2].dpdx; + float voz = extent.param[3].start; + float dvoz = extent.param[3].dpdx; + float in = extent.param[4].start; + float inz = extent.param[4].dpdx; + +// int srctrans = polydata.transparency; +// int desttrans = 32 - polydata.transparency; + + UINT32 umask = (((polydata.texture_param & TRI_PARAM_TEXTURE_MIRROR_U) ? 64 : 32) << texture->width) - 1; + UINT32 vmask = (((polydata.texture_param & TRI_PARAM_TEXTURE_MIRROR_V) ? 64 : 32) << texture->height) - 1; + UINT32 width = 6 + texture->width; + + for (int x = extent.startx; x < extent.stopx; x++) + { + if (z < zb[x]) + { + UINT32 texel; + TEX_FETCH(); + + UINT32 fa = texel >> 24; + if (fa != 0) + { + int ii = (int)in; + + UINT32 r = ((texel & 0x00ff0000) * ii) >> 8; + UINT32 g = ((texel & 0x0000ff00) * ii) >> 8; + UINT32 b = ((texel & 0x000000ff) * ii) >> 8; + + r = (r * fa) >> 8; + g = (g * fa) >> 8; + b = (b * fa) >> 8; + + UINT32 orig = fb[x]; + + int minalpha = 255 - fa; + r += ((orig & 0x00ff0000) * minalpha) >> 8; + g += ((orig & 0x0000ff00) * minalpha) >> 8; + b += ((orig & 0x000000ff) * minalpha) >> 8; + + fb[x] = 0xff000000 | (r & 0xff0000) | (g & 0xff00) | (b & 0xff); + zb[x] = z; + } + } + + ooz += dooz; + uoz += duoz; + voz += dvoz; + in += inz; + z += dz; + } } \ No newline at end of file