Split Taito TC0780FPA into its own device [Ville Linde]

This commit is contained in:
Ville Linde 2015-12-18 22:04:25 +02:00
parent b4329313f9
commit 0df7787f16
7 changed files with 628 additions and 513 deletions

View File

@ -3662,6 +3662,8 @@ files {
MAME_DIR .. "src/mame/video/tc0110pcr.h",
MAME_DIR .. "src/mame/video/tc0180vcu.cpp",
MAME_DIR .. "src/mame/video/tc0180vcu.h",
MAME_DIR .. "src/mame/video/tc0780fpa.cpp",
MAME_DIR .. "src/mame/video/tc0780fpa.h",
}
createMAMEProjects(_target, _subtarget, "tatsumi")

View File

@ -860,63 +860,17 @@ WRITE16_MEMBER(taitojc_state::dsp_rom_w)
}
}
WRITE16_MEMBER(taitojc_state::dsp_texture_w)
{
int index;
int x, y;
x = (m_dsp_tex_offset >> 0 & 0x1f) | (m_dsp_tex_offset >> 5 & 0x20);
y = (m_dsp_tex_offset >> 5 & 0x1f) | (m_dsp_tex_offset >> 6 & 0x20);
index = (((m_texture_y * 32) + y) * 2048) + ((m_texture_x * 32) + x);
m_texture[index] = data & 0xff;
m_dsp_tex_offset++;
}
READ16_MEMBER(taitojc_state::dsp_texaddr_r)
{
return m_dsp_tex_address;
}
WRITE16_MEMBER(taitojc_state::dsp_texaddr_w)
{
m_dsp_tex_address = data;
m_texture_x = (((data >> 0) & 0x1f) << 1) | ((data >> 12) & 0x1);
m_texture_y = (((data >> 5) & 0x1f) << 1) | ((data >> 13) & 0x1);
m_dsp_tex_offset = 0;
}
WRITE16_MEMBER(taitojc_state::dsp_polygon_fifo_w)
{
assert (m_polygon_fifo_ptr < TAITOJC_POLYGON_FIFO_SIZE); // never happens
m_polygon_fifo[m_polygon_fifo_ptr++] = data;
}
WRITE16_MEMBER(taitojc_state::dsp_unk2_w)
{
if (offset == 0)
{
taitojc_clear_frame();
m_renderer->render_polygons(m_polygon_fifo.get(), m_polygon_fifo_ptr);
m_polygon_fifo_ptr = 0;
}
}
static ADDRESS_MAP_START( tms_program_map, AS_PROGRAM, 16, taitojc_state )
AM_RANGE(0x0000, 0x1fff) AM_RAM AM_MIRROR(0x4000)
AM_RANGE(0x6000, 0x7fff) AM_RAM
ADDRESS_MAP_END
static ADDRESS_MAP_START( tms_data_map, AS_DATA, 16, taitojc_state )
AM_RANGE(0x6a01, 0x6a02) AM_WRITE(dsp_unk2_w)
AM_RANGE(0x6a01, 0x6a02) AM_DEVWRITE("tc0780fpa", tc0780fpa_device, render_w)
AM_RANGE(0x6a11, 0x6a12) AM_NOP // same as 0x6a01..02 for the second renderer chip?
AM_RANGE(0x6b20, 0x6b20) AM_WRITE(dsp_polygon_fifo_w)
AM_RANGE(0x6b22, 0x6b22) AM_WRITE(dsp_texture_w)
AM_RANGE(0x6b23, 0x6b23) AM_READWRITE(dsp_texaddr_r, dsp_texaddr_w)
AM_RANGE(0x6b20, 0x6b20) AM_DEVWRITE("tc0780fpa", tc0780fpa_device, poly_fifo_w)
AM_RANGE(0x6b22, 0x6b22) AM_DEVWRITE("tc0780fpa", tc0780fpa_device, tex_w)
AM_RANGE(0x6b23, 0x6b23) AM_DEVREADWRITE("tc0780fpa", tc0780fpa_device, tex_addr_r, tex_addr_w)
AM_RANGE(0x6c00, 0x6c01) AM_READWRITE(dsp_rom_r, dsp_rom_w)
AM_RANGE(0x7000, 0x7002) AM_WRITE(dsp_math_projection_w)
AM_RANGE(0x7010, 0x7012) AM_WRITE(dsp_math_intersection_w)
@ -1098,13 +1052,7 @@ void taitojc_state::machine_reset()
m_mcu_data_main = 0;
m_mcu_data_hc11 = 0;
m_texture_x = 0;
m_texture_y = 0;
m_dsp_rom_pos = 0;
m_dsp_tex_address = 0;
m_dsp_tex_offset = 0;
m_polygon_fifo_ptr = 0;
memset(m_viewport_data, 0, sizeof(m_viewport_data));
memset(m_projection_data, 0, sizeof(m_projection_data));
@ -1117,17 +1065,12 @@ void taitojc_state::machine_reset()
void taitojc_state::machine_start()
{
// register for savestates
save_item(NAME(m_texture_x));
save_item(NAME(m_texture_y));
save_item(NAME(m_dsp_rom_pos));
save_item(NAME(m_dsp_tex_address));
save_item(NAME(m_dsp_tex_offset));
save_item(NAME(m_first_dsp_reset));
save_item(NAME(m_viewport_data));
save_item(NAME(m_projection_data));
save_item(NAME(m_intersection_data));
save_item(NAME(m_gfx_index));
save_item(NAME(m_polygon_fifo_ptr));
save_item(NAME(m_mcu_comm_main));
save_item(NAME(m_mcu_comm_hc11));
@ -1177,6 +1120,8 @@ static MACHINE_CONFIG_START( taitojc, taitojc_state )
MCFG_PALETTE_ADD("palette", 32768)
MCFG_DEVICE_ADD("tc0780fpa", TC0780FPA, 0)
/* sound hardware */
MCFG_FRAGMENT_ADD(taito_en_sound)
MACHINE_CONFIG_END
@ -1225,8 +1170,6 @@ READ16_MEMBER(taitojc_state::dendego2_dsp_idle_skip_r)
DRIVER_INIT_MEMBER(taitojc_state,taitojc)
{
m_polygon_fifo = std::make_unique<UINT16[]>(TAITOJC_POLYGON_FIFO_SIZE);
m_has_dsp_hack = 1;
if (DSP_IDLESKIP)

View File

@ -530,6 +530,7 @@ WRITE16_MEMBER(taitopjc_state::tms_dspshare_w)
static ADDRESS_MAP_START( tms_program_map, AS_PROGRAM, 16, taitopjc_state )
AM_RANGE(0x0000, 0x3fff) AM_ROM AM_REGION("user2", 0)
AM_RANGE(0x5000, 0xefff) AM_ROM AM_REGION("user2", 0xa000)
ADDRESS_MAP_END
static ADDRESS_MAP_START( tms_data_map, AS_DATA, 16, taitopjc_state )

View File

@ -6,42 +6,9 @@
*************************************************************************/
#include "video/poly.h"
#include "video/tc0780fpa.h"
#include "machine/taitoio.h"
#define TAITOJC_POLYGON_FIFO_SIZE 0x20000
struct taitojc_polydata
{
int tex_base_x;
int tex_base_y;
int tex_wrap_x;
int tex_wrap_y;
};
class taitojc_renderer : public poly_manager<float, taitojc_polydata, 6, 10000>
{
public:
taitojc_renderer(running_machine &machine, bitmap_ind16 *fb, bitmap_ind16 *zb, const UINT8 *texture_ram)
: poly_manager<float, taitojc_polydata, 6, 10000>(machine)
{
m_framebuffer = fb;
m_zbuffer = zb;
m_texture = texture_ram;
}
void render_solid_scan(INT32 scanline, const extent_t &extent, const taitojc_polydata &extradata, int threadid);
void render_shade_scan(INT32 scanline, const extent_t &extent, const taitojc_polydata &extradata, int threadid);
void render_texture_scan(INT32 scanline, const extent_t &extent, const taitojc_polydata &extradata, int threadid);
void render_polygons(UINT16 *polygon_fifo, int length);
private:
bitmap_ind16 *m_framebuffer;
bitmap_ind16 *m_zbuffer;
const UINT8 *m_texture;
};
class taitojc_state : public driver_device
{
public:
@ -60,7 +27,8 @@ public:
m_gfxdecode(*this, "gfxdecode"),
m_screen(*this, "screen"),
m_palette(*this, "palette"),
m_analog_ports(*this, "AN")
m_analog_ports(*this, "AN"),
m_tc0780fpa(*this, "tc0780fpa")
{
m_mcu_output = 0;
m_speed_meter = 0;
@ -85,33 +53,21 @@ public:
required_device<palette_device> m_palette;
optional_ioport_array<8> m_analog_ports;
taitojc_renderer *m_renderer;
int m_texture_x;
int m_texture_y;
required_device<tc0780fpa_device> m_tc0780fpa;
UINT32 m_dsp_rom_pos;
UINT16 m_dsp_tex_address;
UINT16 m_dsp_tex_offset;
int m_first_dsp_reset;
INT16 m_viewport_data[3];
INT16 m_projection_data[3];
INT16 m_intersection_data[3];
std::unique_ptr<UINT8[]> m_texture;
bitmap_ind16 m_framebuffer;
bitmap_ind16 m_zbuffer;
int m_gfx_index;
UINT32 *m_char_ram;
UINT32 *m_tile_ram;
tilemap_t *m_tilemap;
std::unique_ptr<UINT16[]> m_polygon_fifo;
int m_polygon_fifo_ptr;
UINT8 m_mcu_comm_main;
UINT8 m_mcu_comm_hc11;
UINT8 m_mcu_data_main;

View File

@ -318,14 +318,6 @@ void taitojc_state::video_start()
/* create the char set (gfx will then be updated dynamically from RAM) */
m_gfxdecode->set_gfx(m_gfx_index, global_alloc(gfx_element(m_palette, taitojc_char_layout, (UINT8 *)m_char_ram, 0, m_palette->entries() / 16, 0)));
m_texture = std::make_unique<UINT8[]>(0x400000);
m_screen->register_screen_bitmap(m_framebuffer);
m_screen->register_screen_bitmap(m_zbuffer);
/* create renderer */
m_renderer = auto_alloc(machine(), taitojc_renderer(machine(), &m_framebuffer, &m_zbuffer, m_texture.get()));
}
UINT32 taitojc_state::screen_update_taitojc(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
@ -338,7 +330,7 @@ UINT32 taitojc_state::screen_update_taitojc(screen_device &screen, bitmap_ind16
draw_object_bank(bitmap, cliprect, 2, 0);
// 3D layer
copybitmap_trans(bitmap, m_framebuffer, 0, 0, 0, 0, cliprect, 0);
m_tc0780fpa->draw(bitmap, cliprect);
// high priority objects
draw_object_bank(bitmap, cliprect, 0, 1);
@ -375,396 +367,3 @@ UINT32 taitojc_state::screen_update_dendego(screen_device &screen, bitmap_ind16
return screen_update_taitojc(screen, bitmap, cliprect);
}
void taitojc_renderer::render_solid_scan(INT32 scanline, const extent_t &extent, const taitojc_polydata &extradata, int threadid)
{
float z = extent.param[0].start;
int color = extent.param[1].start;
float dz = extent.param[0].dpdx;
UINT16 *fb = &m_framebuffer->pix16(scanline);
UINT16 *zb = &m_zbuffer->pix16(scanline);
for (int x = extent.startx; x < extent.stopx; x++)
{
int iz = (int)z & 0xffff;
if (iz <= zb[x])
{
fb[x] = color;
zb[x] = iz;
}
z += dz;
}
}
void taitojc_renderer::render_shade_scan(INT32 scanline, const extent_t &extent, const taitojc_polydata &extradata, int threadid)
{
float z = extent.param[0].start;
float color = extent.param[1].start;
float dz = extent.param[0].dpdx;
float dcolor = extent.param[1].dpdx;
UINT16 *fb = &m_framebuffer->pix16(scanline);
UINT16 *zb = &m_zbuffer->pix16(scanline);
for (int x = extent.startx; x < extent.stopx; x++)
{
int ic = (int)color & 0xffff;
int iz = (int)z & 0xffff;
if (iz <= zb[x])
{
fb[x] = ic;
zb[x] = iz;
}
color += dcolor;
z += dz;
}
}
void taitojc_renderer::render_texture_scan(INT32 scanline, const extent_t &extent, const taitojc_polydata &extradata, int threadid)
{
float z = extent.param[0].start;
float u = extent.param[1].start;
float v = extent.param[2].start;
float color = extent.param[3].start;
float dz = extent.param[0].dpdx;
float du = extent.param[1].dpdx;
float dv = extent.param[2].dpdx;
float dcolor = extent.param[3].dpdx;
UINT16 *fb = &m_framebuffer->pix16(scanline);
UINT16 *zb = &m_zbuffer->pix16(scanline);
int tex_wrap_x = extradata.tex_wrap_x;
int tex_wrap_y = extradata.tex_wrap_y;
int tex_base_x = extradata.tex_base_x;
int tex_base_y = extradata.tex_base_y;
for (int x = extent.startx; x < extent.stopx; x++)
{
int iu, iv;
UINT8 texel;
int palette = ((int)color & 0x7f) << 8;
int iz = (int)z & 0xffff;
if (!tex_wrap_x)
{
iu = ((int)u >> 4) & 0x7ff;
}
else
{
iu = (tex_base_x + (((int)u >> 4) & 0x3f)) & 0x7ff;
}
if (!tex_wrap_y)
{
iv = ((int)v >> 4) & 0x7ff;
}
else
{
iv = (tex_base_y + (((int)v >> 4) & 0x3f)) & 0x7ff;
}
texel = m_texture[(iv * 2048) + iu];
if (iz <= zb[x] && texel != 0)
{
fb[x] = palette | texel;
zb[x] = iz;
}
u += du;
v += dv;
color += dcolor;
z += dz;
}
}
void taitojc_renderer::render_polygons(UINT16 *polygon_fifo, int length)
{
const rectangle visarea = machine().first_screen()->visible_area();
vertex_t vert[4];
int i;
int ptr;
ptr = 0;
while (ptr < length)
{
UINT16 cmd = polygon_fifo[ptr++];
switch (cmd & 0x7)
{
// screen global clipping for 3d(?)
case 0x00:
{
UINT16 min_x,min_y,min_z,max_x,max_y,max_z;
min_x = polygon_fifo[ptr+1];
min_y = polygon_fifo[ptr+0];
min_z = polygon_fifo[ptr+2];
max_x = polygon_fifo[ptr+4];
max_y = polygon_fifo[ptr+3];
max_z = polygon_fifo[ptr+5];
/* let's check if we need to implement this ... */
if(min_x != 0 || min_y != 0 || min_z != 0 || max_x != 512 || max_y != 400 || max_z != 0x7fff)
{
printf("CMD %04x\n",cmd);
printf("MIN Y %04x\n",polygon_fifo[ptr+0]);
printf("MIN X %04x\n",polygon_fifo[ptr+1]);
printf("MIN Z %04x\n",polygon_fifo[ptr+2]);
printf("MAX Y %04x\n",polygon_fifo[ptr+3]);
printf("MAX X %04x\n",polygon_fifo[ptr+4]);
printf("MAX Z %04x\n",polygon_fifo[ptr+5]);
}
ptr += 6;
break;
}
// Gouraud Shaded Triangle (Landing Gear)
case 0x01:
{
// 0x00: Command ID (0x0001)
// 0x01: Vertex 1 color
// 0x02: Vertex 1 Y
// 0x03: Vertex 1 X
// 0x04: Vertex 1 Z
// 0x05: Vertex 2 color
// 0x06: Vertex 2 Y
// 0x07: Vertex 2 X
// 0x08: Vertex 2 Z
// 0x09: Vertex 3 color
// 0x0a: Vertex 3 Y
// 0x0b: Vertex 3 X
// 0x0c: Vertex 3 Z
#if 0
printf("CMD1: ");
for (i=0; i < 0x0c; i++)
{
printf("%04X ", polygon_fifo[ptr+i]);
}
printf("\n");
#endif
for (i=0; i < 3; i++)
{
vert[i].p[1] = polygon_fifo[ptr++];
vert[i].y = (INT16)(polygon_fifo[ptr++]);
vert[i].x = (INT16)(polygon_fifo[ptr++]);
vert[i].p[0] = (UINT16)(polygon_fifo[ptr++]);
}
if (vert[0].p[0] < 0x8000 && vert[1].p[0] < 0x8000 && vert[2].p[0] < 0x8000)
{
if (vert[0].p[1] == vert[1].p[1] &&
vert[1].p[1] == vert[2].p[1])
{
// optimization: all colours the same -> render solid
render_triangle(visarea, render_delegate(FUNC(taitojc_renderer::render_solid_scan), this), 2, vert[0], vert[1], vert[2]);
}
else
{
render_triangle(visarea, render_delegate(FUNC(taitojc_renderer::render_shade_scan), this), 2, vert[0], vert[1], vert[2]);
}
}
break;
}
// Textured Triangle
case 0x03:
{
// 0x00: Command ID (0x0003)
// 0x01: Texture base
// 0x02: Vertex 1 Palette
// 0x03: Vertex 1 V
// 0x04: Vertex 1 U
// 0x05: Vertex 1 Y
// 0x06: Vertex 1 X
// 0x07: Vertex 1 Z
// 0x08: Vertex 2 Palette
// 0x09: Vertex 2 V
// 0x0a: Vertex 2 U
// 0x0b: Vertex 2 Y
// 0x0c: Vertex 2 X
// 0x0d: Vertex 2 Z
// 0x0e: Vertex 3 Palette
// 0x0f: Vertex 3 V
// 0x10: Vertex 3 U
// 0x11: Vertex 3 Y
// 0x12: Vertex 3 X
// 0x13: Vertex 3 Z
#if 0
printf("CMD3: ");
for (i=0; i < 0x13; i++)
{
printf("%04X ", polygon_fifo[ptr+i]);
}
printf("\n");
#endif
taitojc_polydata &extra = object_data_alloc();
UINT16 texbase = polygon_fifo[ptr++];
extra.tex_base_x = ((texbase >> 0) & 0xff) << 4;
extra.tex_base_y = ((texbase >> 8) & 0xff) << 4;
extra.tex_wrap_x = (cmd & 0xc0) ? 1 : 0;
extra.tex_wrap_y = (cmd & 0x30) ? 1 : 0;
for (i=0; i < 3; i++)
{
vert[i].p[3] = polygon_fifo[ptr++] + 0.5; // palette
vert[i].p[2] = (UINT16)(polygon_fifo[ptr++]);
vert[i].p[1] = (UINT16)(polygon_fifo[ptr++]);
vert[i].y = (INT16)(polygon_fifo[ptr++]);
vert[i].x = (INT16)(polygon_fifo[ptr++]);
vert[i].p[0] = (UINT16)(polygon_fifo[ptr++]);
}
if (vert[0].p[0] < 0x8000 && vert[1].p[0] < 0x8000 && vert[2].p[0] < 0x8000)
{
render_triangle(visarea, render_delegate(FUNC(taitojc_renderer::render_texture_scan), this), 4, vert[0], vert[1], vert[2]);
}
break;
}
// Gouraud shaded Quad
case 0x04:
{
// 0x00: Command ID (0x0004)
// 0x01: Vertex 1 color
// 0x02: Vertex 1 Y
// 0x03: Vertex 1 X
// 0x04: Vertex 1 Z
// 0x05: Vertex 2 color
// 0x06: Vertex 2 Y
// 0x07: Vertex 2 X
// 0x08: Vertex 2 Z
// 0x09: Vertex 3 color
// 0x0a: Vertex 3 Y
// 0x0b: Vertex 3 X
// 0x0c: Vertex 3 Z
// 0x0d: Vertex 4 color
// 0x0e: Vertex 4 Y
// 0x0f: Vertex 4 X
// 0x10: Vertex 4 Z
#if 0
printf("CMD4: ");
for (i=0; i < 0x10; i++)
{
printf("%04X ", polygon_fifo[ptr+i]);
}
printf("\n");
#endif
for (i=0; i < 4; i++)
{
vert[i].p[1] = polygon_fifo[ptr++];
vert[i].y = (INT16)(polygon_fifo[ptr++]);
vert[i].x = (INT16)(polygon_fifo[ptr++]);
vert[i].p[0] = (UINT16)(polygon_fifo[ptr++]);
}
if (vert[0].p[0] < 0x8000 && vert[1].p[0] < 0x8000 && vert[2].p[0] < 0x8000 && vert[3].p[0] < 0x8000)
{
if (vert[0].p[1] == vert[1].p[1] &&
vert[1].p[1] == vert[2].p[1] &&
vert[2].p[1] == vert[3].p[1])
{
// optimization: all colours the same -> render solid
render_polygon<4>(visarea, render_delegate(FUNC(taitojc_renderer::render_solid_scan), this), 2, vert);
}
else
{
render_polygon<4>(visarea, render_delegate(FUNC(taitojc_renderer::render_shade_scan), this), 2, vert);
}
}
break;
}
// Textured Quad
case 0x06:
{
// 0x00: Command ID (0x0006)
// 0x01: Texture base
// 0x02: Vertex 1 Palette
// 0x03: Vertex 1 V
// 0x04: Vertex 1 U
// 0x05: Vertex 1 Y
// 0x06: Vertex 1 X
// 0x07: Vertex 1 Z
// 0x08: Vertex 2 Palette
// 0x09: Vertex 2 V
// 0x0a: Vertex 2 U
// 0x0b: Vertex 2 Y
// 0x0c: Vertex 2 X
// 0x0d: Vertex 2 Z
// 0x0e: Vertex 3 Palette
// 0x0f: Vertex 3 V
// 0x10: Vertex 3 U
// 0x11: Vertex 3 Y
// 0x12: Vertex 3 X
// 0x13: Vertex 3 Z
// 0x14: Vertex 4 Palette
// 0x15: Vertex 4 V
// 0x16: Vertex 4 U
// 0x17: Vertex 4 Y
// 0x18: Vertex 4 X
// 0x19: Vertex 4 Z
#if 0
printf("CMD6: ");
for (i=0; i < 0x19; i++)
{
printf("%04X ", polygon_fifo[ptr+i]);
}
printf("\n");
#endif
taitojc_polydata &extra = object_data_alloc();
UINT16 texbase = polygon_fifo[ptr++];
extra.tex_base_x = ((texbase >> 0) & 0xff) << 4;
extra.tex_base_y = ((texbase >> 8) & 0xff) << 4;
extra.tex_wrap_x = (cmd & 0xc0) ? 1 : 0;
extra.tex_wrap_y = (cmd & 0x30) ? 1 : 0;
for (i=0; i < 4; i++)
{
vert[i].p[3] = polygon_fifo[ptr++] + 0.5; // palette
vert[i].p[2] = (UINT16)(polygon_fifo[ptr++]);
vert[i].p[1] = (UINT16)(polygon_fifo[ptr++]);
vert[i].y = (INT16)(polygon_fifo[ptr++]);
vert[i].x = (INT16)(polygon_fifo[ptr++]);
vert[i].p[0] = (UINT16)(polygon_fifo[ptr++]);
}
if (vert[0].p[0] < 0x8000 && vert[1].p[0] < 0x8000 && vert[2].p[0] < 0x8000 && vert[3].p[0] < 0x8000)
{
render_polygon<4>(visarea, render_delegate(FUNC(taitojc_renderer::render_texture_scan), this), 4, vert);
}
break;
}
default:
{
printf("render_polygons: unknown command %04X %d\n", cmd,ptr);
break;
}
}
}
wait("Finished render");
}
void taitojc_state::taitojc_clear_frame()
{
m_framebuffer.fill(0, m_screen->visible_area());
m_zbuffer.fill(0xffff, m_screen->visible_area());
}

View File

@ -0,0 +1,534 @@
// license:LGPL-2.1+
// copyright-holders:Ville Linde, Angelo Salese, hap
// Taito TC0780FPA Polygon Renderer
#include "emu.h"
#include "tc0780fpa.h"
#define POLY_FIFO_SIZE 0x20000
tc0780fpa_renderer::tc0780fpa_renderer(device_t &parent, screen_device &screen, const UINT8 *texture_ram)
: poly_manager<float, tc0780fpa_polydata, 6, 10000>(screen)
{
int width = screen.width();
int height = screen.height();
m_fb = std::make_unique<bitmap_ind16>(width, height);
m_zb = std::make_unique<bitmap_ind16>(width, height);
m_texture = texture_ram;
m_cliprect = screen.cliprect();
// save state
parent.save_item(NAME(*m_fb));
parent.save_item(NAME(*m_zb));
}
void tc0780fpa_renderer::clear_frame()
{
m_fb->fill(0, m_cliprect);
m_zb->fill(0xffff, m_cliprect);
}
void tc0780fpa_renderer::draw(bitmap_ind16 &bitmap, const rectangle &cliprect)
{
copybitmap_trans(bitmap, *m_fb, 0, 0, 0, 0, cliprect, 0);
}
void tc0780fpa_renderer::render_solid_scan(INT32 scanline, const extent_t &extent, const tc0780fpa_polydata &extradata, int threadid)
{
float z = extent.param[0].start;
int color = extent.param[1].start;
float dz = extent.param[0].dpdx;
UINT16 *fb = &m_fb->pix16(scanline);
UINT16 *zb = &m_zb->pix16(scanline);
for (int x = extent.startx; x < extent.stopx; x++)
{
int iz = (int)z & 0xffff;
if (iz <= zb[x])
{
fb[x] = color;
zb[x] = iz;
}
z += dz;
}
}
void tc0780fpa_renderer::render_shade_scan(INT32 scanline, const extent_t &extent, const tc0780fpa_polydata &extradata, int threadid)
{
float z = extent.param[0].start;
float color = extent.param[1].start;
float dz = extent.param[0].dpdx;
float dcolor = extent.param[1].dpdx;
UINT16 *fb = &m_fb->pix16(scanline);
UINT16 *zb = &m_zb->pix16(scanline);
for (int x = extent.startx; x < extent.stopx; x++)
{
int ic = (int)color & 0xffff;
int iz = (int)z & 0xffff;
if (iz <= zb[x])
{
fb[x] = ic;
zb[x] = iz;
}
color += dcolor;
z += dz;
}
}
void tc0780fpa_renderer::render_texture_scan(INT32 scanline, const extent_t &extent, const tc0780fpa_polydata &extradata, int threadid)
{
float z = extent.param[0].start;
float u = extent.param[1].start;
float v = extent.param[2].start;
float color = extent.param[3].start;
float dz = extent.param[0].dpdx;
float du = extent.param[1].dpdx;
float dv = extent.param[2].dpdx;
float dcolor = extent.param[3].dpdx;
UINT16 *fb = &m_fb->pix16(scanline);
UINT16 *zb = &m_zb->pix16(scanline);
int tex_wrap_x = extradata.tex_wrap_x;
int tex_wrap_y = extradata.tex_wrap_y;
int tex_base_x = extradata.tex_base_x;
int tex_base_y = extradata.tex_base_y;
for (int x = extent.startx; x < extent.stopx; x++)
{
int iu, iv;
UINT8 texel;
int palette = ((int)color & 0x7f) << 8;
int iz = (int)z & 0xffff;
if (!tex_wrap_x)
{
iu = ((int)u >> 4) & 0x7ff;
}
else
{
iu = (tex_base_x + (((int)u >> 4) & 0x3f)) & 0x7ff;
}
if (!tex_wrap_y)
{
iv = ((int)v >> 4) & 0x7ff;
}
else
{
iv = (tex_base_y + (((int)v >> 4) & 0x3f)) & 0x7ff;
}
texel = m_texture[(iv * 2048) + iu];
if (iz <= zb[x] && texel != 0)
{
fb[x] = palette | texel;
zb[x] = iz;
}
u += du;
v += dv;
color += dcolor;
z += dz;
}
}
void tc0780fpa_renderer::render_polygons(UINT16 *polygon_fifo, int length)
{
vertex_t vert[4];
int i;
int ptr;
ptr = 0;
while (ptr < length)
{
UINT16 cmd = polygon_fifo[ptr++];
switch (cmd & 0x7)
{
// screen global clipping for 3d(?)
case 0x00:
{
UINT16 min_x,min_y,min_z,max_x,max_y,max_z;
min_x = polygon_fifo[ptr+1];
min_y = polygon_fifo[ptr+0];
min_z = polygon_fifo[ptr+2];
max_x = polygon_fifo[ptr+4];
max_y = polygon_fifo[ptr+3];
max_z = polygon_fifo[ptr+5];
/* let's check if we need to implement this ... */
if(min_x != 0 || min_y != 0 || min_z != 0 || max_x != 512 || max_y != 400 || max_z != 0x7fff)
{
printf("CMD %04x\n",cmd);
printf("MIN Y %04x\n",polygon_fifo[ptr+0]);
printf("MIN X %04x\n",polygon_fifo[ptr+1]);
printf("MIN Z %04x\n",polygon_fifo[ptr+2]);
printf("MAX Y %04x\n",polygon_fifo[ptr+3]);
printf("MAX X %04x\n",polygon_fifo[ptr+4]);
printf("MAX Z %04x\n",polygon_fifo[ptr+5]);
}
ptr += 6;
break;
}
// Gouraud Shaded Triangle (Landing Gear)
case 0x01:
{
// 0x00: Command ID (0x0001)
// 0x01: Vertex 1 color
// 0x02: Vertex 1 Y
// 0x03: Vertex 1 X
// 0x04: Vertex 1 Z
// 0x05: Vertex 2 color
// 0x06: Vertex 2 Y
// 0x07: Vertex 2 X
// 0x08: Vertex 2 Z
// 0x09: Vertex 3 color
// 0x0a: Vertex 3 Y
// 0x0b: Vertex 3 X
// 0x0c: Vertex 3 Z
#if 0
printf("CMD1: ");
for (i=0; i < 0x0c; i++)
{
printf("%04X ", polygon_fifo[ptr+i]);
}
printf("\n");
#endif
for (i=0; i < 3; i++)
{
vert[i].p[1] = polygon_fifo[ptr++];
vert[i].y = (INT16)(polygon_fifo[ptr++]);
vert[i].x = (INT16)(polygon_fifo[ptr++]);
vert[i].p[0] = (UINT16)(polygon_fifo[ptr++]);
}
if (vert[0].p[0] < 0x8000 && vert[1].p[0] < 0x8000 && vert[2].p[0] < 0x8000)
{
if (vert[0].p[1] == vert[1].p[1] &&
vert[1].p[1] == vert[2].p[1])
{
// optimization: all colours the same -> render solid
render_triangle(m_cliprect, render_delegate(FUNC(tc0780fpa_renderer::render_solid_scan), this), 2, vert[0], vert[1], vert[2]);
}
else
{
render_triangle(m_cliprect, render_delegate(FUNC(tc0780fpa_renderer::render_shade_scan), this), 2, vert[0], vert[1], vert[2]);
}
}
break;
}
// Textured Triangle
case 0x03:
{
// 0x00: Command ID (0x0003)
// 0x01: Texture base
// 0x02: Vertex 1 Palette
// 0x03: Vertex 1 V
// 0x04: Vertex 1 U
// 0x05: Vertex 1 Y
// 0x06: Vertex 1 X
// 0x07: Vertex 1 Z
// 0x08: Vertex 2 Palette
// 0x09: Vertex 2 V
// 0x0a: Vertex 2 U
// 0x0b: Vertex 2 Y
// 0x0c: Vertex 2 X
// 0x0d: Vertex 2 Z
// 0x0e: Vertex 3 Palette
// 0x0f: Vertex 3 V
// 0x10: Vertex 3 U
// 0x11: Vertex 3 Y
// 0x12: Vertex 3 X
// 0x13: Vertex 3 Z
#if 0
printf("CMD3: ");
for (i=0; i < 0x13; i++)
{
printf("%04X ", polygon_fifo[ptr+i]);
}
printf("\n");
#endif
tc0780fpa_polydata &extra = object_data_alloc();
UINT16 texbase = polygon_fifo[ptr++];
extra.tex_base_x = ((texbase >> 0) & 0xff) << 4;
extra.tex_base_y = ((texbase >> 8) & 0xff) << 4;
extra.tex_wrap_x = (cmd & 0xc0) ? 1 : 0;
extra.tex_wrap_y = (cmd & 0x30) ? 1 : 0;
for (i=0; i < 3; i++)
{
vert[i].p[3] = polygon_fifo[ptr++] + 0.5; // palette
vert[i].p[2] = (UINT16)(polygon_fifo[ptr++]);
vert[i].p[1] = (UINT16)(polygon_fifo[ptr++]);
vert[i].y = (INT16)(polygon_fifo[ptr++]);
vert[i].x = (INT16)(polygon_fifo[ptr++]);
vert[i].p[0] = (UINT16)(polygon_fifo[ptr++]);
}
if (vert[0].p[0] < 0x8000 && vert[1].p[0] < 0x8000 && vert[2].p[0] < 0x8000)
{
render_triangle(m_cliprect, render_delegate(FUNC(tc0780fpa_renderer::render_texture_scan), this), 4, vert[0], vert[1], vert[2]);
}
break;
}
// Gouraud shaded Quad
case 0x04:
{
// 0x00: Command ID (0x0004)
// 0x01: Vertex 1 color
// 0x02: Vertex 1 Y
// 0x03: Vertex 1 X
// 0x04: Vertex 1 Z
// 0x05: Vertex 2 color
// 0x06: Vertex 2 Y
// 0x07: Vertex 2 X
// 0x08: Vertex 2 Z
// 0x09: Vertex 3 color
// 0x0a: Vertex 3 Y
// 0x0b: Vertex 3 X
// 0x0c: Vertex 3 Z
// 0x0d: Vertex 4 color
// 0x0e: Vertex 4 Y
// 0x0f: Vertex 4 X
// 0x10: Vertex 4 Z
#if 0
printf("CMD4: ");
for (i=0; i < 0x10; i++)
{
printf("%04X ", polygon_fifo[ptr+i]);
}
printf("\n");
#endif
for (i=0; i < 4; i++)
{
vert[i].p[1] = polygon_fifo[ptr++];
vert[i].y = (INT16)(polygon_fifo[ptr++]);
vert[i].x = (INT16)(polygon_fifo[ptr++]);
vert[i].p[0] = (UINT16)(polygon_fifo[ptr++]);
}
if (vert[0].p[0] < 0x8000 && vert[1].p[0] < 0x8000 && vert[2].p[0] < 0x8000 && vert[3].p[0] < 0x8000)
{
if (vert[0].p[1] == vert[1].p[1] &&
vert[1].p[1] == vert[2].p[1] &&
vert[2].p[1] == vert[3].p[1])
{
// optimization: all colours the same -> render solid
render_polygon<4>(m_cliprect, render_delegate(FUNC(tc0780fpa_renderer::render_solid_scan), this), 2, vert);
}
else
{
render_polygon<4>(m_cliprect, render_delegate(FUNC(tc0780fpa_renderer::render_shade_scan), this), 2, vert);
}
}
break;
}
// Textured Quad
case 0x06:
{
// 0x00: Command ID (0x0006)
// 0x01: Texture base
// 0x02: Vertex 1 Palette
// 0x03: Vertex 1 V
// 0x04: Vertex 1 U
// 0x05: Vertex 1 Y
// 0x06: Vertex 1 X
// 0x07: Vertex 1 Z
// 0x08: Vertex 2 Palette
// 0x09: Vertex 2 V
// 0x0a: Vertex 2 U
// 0x0b: Vertex 2 Y
// 0x0c: Vertex 2 X
// 0x0d: Vertex 2 Z
// 0x0e: Vertex 3 Palette
// 0x0f: Vertex 3 V
// 0x10: Vertex 3 U
// 0x11: Vertex 3 Y
// 0x12: Vertex 3 X
// 0x13: Vertex 3 Z
// 0x14: Vertex 4 Palette
// 0x15: Vertex 4 V
// 0x16: Vertex 4 U
// 0x17: Vertex 4 Y
// 0x18: Vertex 4 X
// 0x19: Vertex 4 Z
#if 0
printf("CMD6: ");
for (i=0; i < 0x19; i++)
{
printf("%04X ", polygon_fifo[ptr+i]);
}
printf("\n");
#endif
tc0780fpa_polydata &extra = object_data_alloc();
UINT16 texbase = polygon_fifo[ptr++];
extra.tex_base_x = ((texbase >> 0) & 0xff) << 4;
extra.tex_base_y = ((texbase >> 8) & 0xff) << 4;
extra.tex_wrap_x = (cmd & 0xc0) ? 1 : 0;
extra.tex_wrap_y = (cmd & 0x30) ? 1 : 0;
for (i=0; i < 4; i++)
{
vert[i].p[3] = polygon_fifo[ptr++] + 0.5; // palette
vert[i].p[2] = (UINT16)(polygon_fifo[ptr++]);
vert[i].p[1] = (UINT16)(polygon_fifo[ptr++]);
vert[i].y = (INT16)(polygon_fifo[ptr++]);
vert[i].x = (INT16)(polygon_fifo[ptr++]);
vert[i].p[0] = (UINT16)(polygon_fifo[ptr++]);
}
if (vert[0].p[0] < 0x8000 && vert[1].p[0] < 0x8000 && vert[2].p[0] < 0x8000 && vert[3].p[0] < 0x8000)
{
render_polygon<4>(m_cliprect, render_delegate(FUNC(tc0780fpa_renderer::render_texture_scan), this), 4, vert);
}
break;
}
default:
{
printf("tc0780fpa::render_polygons(): unknown command %04X %d\n", cmd,ptr);
break;
}
}
}
wait("Finished render");
}
const device_type TC0780FPA = &device_creator<tc0780fpa_device>;
tc0780fpa_device::tc0780fpa_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: device_t(mconfig, TC0780FPA, "TC0780FPA Polygon Renderer", tag, owner, clock, "tc0780fpa", __FILE__),
device_video_interface(mconfig, *this)
{
}
//-------------------------------------------------
// device_config_complete - perform any
// operations now that the configuration is
// complete
//-------------------------------------------------
void tc0780fpa_device::device_config_complete()
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void tc0780fpa_device::device_start()
{
m_texture = std::make_unique<UINT8[]>(0x400000);
m_poly_fifo = std::make_unique<UINT16[]>(POLY_FIFO_SIZE);
m_renderer = auto_alloc(machine(), tc0780fpa_renderer(*this, *m_screen, m_texture.get()));
save_pointer(NAME(m_texture.get()), 0x400000);
save_pointer(NAME(m_poly_fifo.get()), POLY_FIFO_SIZE);
save_item(NAME(m_poly_fifo_ptr));
save_item(NAME(m_tex_address));
save_item(NAME(m_tex_offset));
save_item(NAME(m_texbase_x));
save_item(NAME(m_texbase_y));
}
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
void tc0780fpa_device::device_reset()
{
m_poly_fifo_ptr = 0;
}
//-------------------------------------------------
// device_stop - device-specific stop
//-------------------------------------------------
void tc0780fpa_device::device_stop()
{
}
/*****************************************************************************
DEVICE HANDLERS
*****************************************************************************/
READ16_MEMBER(tc0780fpa_device::tex_addr_r)
{
return m_tex_address;
}
WRITE16_MEMBER(tc0780fpa_device::tex_addr_w)
{
m_tex_address = data;
m_texbase_x = (((data >> 0) & 0x1f) << 1) | ((data >> 12) & 0x1);
m_texbase_y = (((data >> 5) & 0x1f) << 1) | ((data >> 13) & 0x1);
m_tex_offset = 0;
}
WRITE16_MEMBER(tc0780fpa_device::tex_w)
{
int x = ((m_tex_offset >> 0) & 0x1f) | ((m_tex_offset >> 5) & 0x20);
int y = ((m_tex_offset >> 5) & 0x1f) | ((m_tex_offset >> 6) & 0x20);
int index = (((m_texbase_y * 32) + y) * 2048) + ((m_texbase_x * 32) + x);
m_texture[index] = data & 0xff;
m_tex_offset++;
}
WRITE16_MEMBER(tc0780fpa_device::poly_fifo_w)
{
assert (m_poly_fifo_ptr < POLY_FIFO_SIZE); // never happens
m_poly_fifo[m_poly_fifo_ptr++] = data;
}
WRITE16_MEMBER(tc0780fpa_device::render_w)
{
if (offset == 0)
{
m_renderer->clear_frame();
m_renderer->render_polygons(m_poly_fifo.get(), m_poly_fifo_ptr);
m_poly_fifo_ptr = 0;
}
}
void tc0780fpa_device::draw(bitmap_ind16 &bitmap, const rectangle &cliprect)
{
m_renderer->draw(bitmap, cliprect);
}

View File

@ -0,0 +1,80 @@
// license:LGPL-2.1+
// copyright-holders:Ville Linde, Angelo Salese, hap
#pragma once
#ifndef __TC0780FPA_H__
#define __TC0780FPA_H__
#include "video/poly.h"
struct tc0780fpa_polydata
{
int tex_base_x;
int tex_base_y;
int tex_wrap_x;
int tex_wrap_y;
};
class tc0780fpa_renderer : public poly_manager<float, tc0780fpa_polydata, 6, 10000>
{
public:
tc0780fpa_renderer(device_t &parent, screen_device &screen, const UINT8 *texture_ram);
~tc0780fpa_renderer() {}
void render_solid_scan(INT32 scanline, const extent_t &extent, const tc0780fpa_polydata &extradata, int threadid);
void render_shade_scan(INT32 scanline, const extent_t &extent, const tc0780fpa_polydata &extradata, int threadid);
void render_texture_scan(INT32 scanline, const extent_t &extent, const tc0780fpa_polydata &extradata, int threadid);
void render_polygons(UINT16 *polygon_fifo, int length);
void draw(bitmap_ind16 &bitmap, const rectangle &cliprect);
void clear_frame();
private:
std::unique_ptr<bitmap_ind16> m_fb;
std::unique_ptr<bitmap_ind16> m_zb;
const UINT8 *m_texture;
rectangle m_cliprect;
};
class tc0780fpa_device : public device_t, public device_video_interface
{
public:
tc0780fpa_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
~tc0780fpa_device() {}
void draw(bitmap_ind16 &bitmap, const rectangle &cliprect);
void texture_write(offs_t address, UINT8 data);
DECLARE_READ16_MEMBER(tex_addr_r);
DECLARE_WRITE16_MEMBER(tex_addr_w);
DECLARE_WRITE16_MEMBER(tex_w);
DECLARE_WRITE16_MEMBER(poly_fifo_w);
DECLARE_WRITE16_MEMBER(render_w);
protected:
// device-level overrides
virtual void device_config_complete() override;
virtual void device_start() override;
virtual void device_stop() override;
virtual void device_reset() override;
private:
std::unique_ptr<UINT8[]> m_texture;
std::unique_ptr<UINT16[]> m_poly_fifo;
int m_poly_fifo_ptr;
tc0780fpa_renderer *m_renderer;
UINT16 m_tex_address;
UINT16 m_tex_offset;
int m_texbase_x;
int m_texbase_y;
};
extern const device_type TC0780FPA;
#endif