diff options
Diffstat (limited to 'src/mame/video/k001005.cpp')
-rw-r--r-- | src/mame/video/k001005.cpp | 1718 |
1 files changed, 471 insertions, 1247 deletions
diff --git a/src/mame/video/k001005.cpp b/src/mame/video/k001005.cpp index d6728ec7281..bbefdb30af0 100644 --- a/src/mame/video/k001005.cpp +++ b/src/mame/video/k001005.cpp @@ -15,9 +15,8 @@ /* TODO: - - Fog equation and parameters are probably not accurate. - Winding Heat (and maybe others) have slight Z-fighting problems. - - 3D in Solar Assault title isn't properly turned off (the SHARC keeps rendering 3D). + - Player car shadow not visible in Winding Heat. Hidden by road, needs polygon priority or something similar? */ @@ -74,12 +73,22 @@ k001005_renderer::k001005_renderer(device_t &parent, screen_device &screen, devi parent.save_item(NAME(m_fog_g)); parent.save_item(NAME(m_fog_b)); parent.save_item(NAME(m_far_z)); - + parent.save_item(NAME(m_fog_start_z)); + parent.save_item(NAME(m_fog_end_z)); + parent.save_item(NAME(m_reg_fog_start)); + parent.save_item(NAME(m_viewport_min_x)); + parent.save_item(NAME(m_viewport_max_x)); + parent.save_item(NAME(m_viewport_min_y)); + parent.save_item(NAME(m_viewport_max_y)); + parent.save_item(NAME(m_viewport_center_x)); + parent.save_item(NAME(m_viewport_center_y)); } void k001005_renderer::reset() { m_3dfifo_ptr = 0; + + m_vertexb_ptr = 0; } void k001005_renderer::push_data(uint32_t data) @@ -108,1352 +117,558 @@ bool k001005_renderer::fifo_filled() return m_3dfifo_ptr > 0; } -void k001005_renderer::set_param(k001005_param param, uint32_t value) -{ - switch (param) - { - case K001005_LIGHT_R: m_light_r = value; break; - case K001005_LIGHT_G: m_light_g = value; break; - case K001005_LIGHT_B: m_light_b = value; break; - case K001005_AMBIENT_R: m_ambient_r = value; break; - case K001005_AMBIENT_G: m_ambient_g = value; break; - case K001005_AMBIENT_B: m_ambient_b = value; break; - case K001005_FOG_R: m_fog_r = value; break; - case K001005_FOG_G: m_fog_g = value; break; - case K001005_FOG_B: m_fog_b = value; break; - case K001005_FAR_Z: - { - uint32_t fz = value << 11; - m_far_z = *(float*)&fz; - if (m_far_z == 0.0f) // just in case... - m_far_z = 1.0f; - break; - } - } -} -void k001005_renderer::render_polygons() +template<bool UseTexture, bool UseVertexColor> +void k001005_renderer::draw_scanline_generic(int32_t scanline, const extent_t& extent, const k001005_polydata& extradata, int threadid) { - vertex_t v[4]; - int poly_type; - int brightness; + float u, v, w, du, dv, dw; + float r, g, b, a, dr, dg, db, da; - vertex_t *vertex1; - vertex_t *vertex2; - vertex_t *vertex3; - vertex_t *vertex4; - - uint32_t *fifo = m_3dfifo.get(); + k001006_device* k001006 = downcast<k001006_device*>(m_k001006); - int index = 0; + uint32_t* const fb = &m_fb[m_fb_page]->pix(scanline); + float* const zb = (float*)&m_zb->pix(scanline); - float fog_density = 1.5f; + float z = extent.param[POLY_Z].start; + float dz = extent.param[POLY_Z].dpdx; + float diff = extent.param[POLY_DIFF].start; + float ddiff = extent.param[POLY_DIFF].dpdx; + float fog = extent.param[POLY_FOG].start; + float dfog = extent.param[POLY_FOG].dpdx; - render_delegate rd_scan_2d = render_delegate(&k001005_renderer::draw_scanline_2d, this); - render_delegate rd_scan_tex2d = render_delegate(&k001005_renderer::draw_scanline_2d_tex, this); - render_delegate rd_scan = render_delegate(&k001005_renderer::draw_scanline, this); - render_delegate rd_scan_tex = render_delegate(&k001005_renderer::draw_scanline_tex, this); - render_delegate rd_scan_gour_blend = render_delegate(&k001005_renderer::draw_scanline_gouraud_blend, this); - render_delegate rd_scan_tex_gouraud = render_delegate(&k001005_renderer::draw_scanline_tex_gouraud, this); + if (UseTexture) + { + u = extent.param[POLY_U].start; + v = extent.param[POLY_V].start; + w = extent.param[POLY_W].start; + du = extent.param[POLY_U].dpdx; + dv = extent.param[POLY_V].dpdx; + dw = extent.param[POLY_W].dpdx; + } - do + if (UseVertexColor) { - uint32_t cmd = fifo[index++]; + r = extent.param[POLY_R].start; + dr = extent.param[POLY_R].dpdx; + g = extent.param[POLY_G].start; + dg = extent.param[POLY_G].dpdx; + b = extent.param[POLY_B].start; + db = extent.param[POLY_B].dpdx; + a = extent.param[POLY_A].start; + da = extent.param[POLY_A].dpdx; + } - // Current guesswork on the command word bits: - // 0x01: Z-buffer disable? - // 0x02: Almost always set (only exception is 0x80000020 in Thunder Hurricane attract mode) - // 0x04: - // 0x08: - // 0x10: Texture mirror enable - // 0x20: Gouraud shading enable? - // 0x40: Unused? - // 0x80: Used by textured polygons. - // 0x100: Alpha blending? Only used by Winding Heat car selection so far. - - if (cmd == 0x800000ae || cmd == 0x8000008e || cmd == 0x80000096 || cmd == 0x800000b6 || - cmd == 0x8000002e || cmd == 0x8000000e || cmd == 0x80000016 || cmd == 0x80000036 || - cmd == 0x800000aa || cmd == 0x800000a8 || cmd == 0x800000b2 || cmd == 0x8000009e || - cmd == 0x80000092 || cmd == 0x8000008a || cmd == 0x80000094 || cmd == 0x8000009a || - cmd == 0x8000009c || cmd == 0x8000008c || cmd == 0x800000ac || cmd == 0x800000b4) - { - // 0x00: xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx Command - // - // 0x01: xxxx---- -------- -------- -------- Texture palette - // 0x01: ----xx-- -------- -------- -------- Unknown flags, set by commands 0x7b...0x7e - // 0x01: ------xx x------- -------- -------- Texture width / 8 - 1 - // 0x01: -------- -xxx---- -------- -------- Texture height / 8 - 1 - // 0x01: -------- -------x xxxx---- -------- Texture page - // 0x01: -------- -------- ----x-x- x-x-x-x- Texture X / 8 - // 0x01: -------- -------- -----x-x -x-x-x-x Texture Y / 8 - - // texture, Z - - int tex_x, tex_y; - uint32_t color = 0; - k001005_polydata &extra = object_data_alloc(); - - uint32_t header = fifo[index++]; - - int last_vertex = 0; - int vert_num = 0; - do - { - int x, y, z; - int16_t tu, tv; + rgbaint_t ambient_color(extradata.ambient_light); + rgbaint_t diffuse_color(extradata.diffuse_light); + rgbaint_t fog_color(extradata.fog_color); - x = (fifo[index] >> 0) & 0x3fff; - y = (fifo[index] >> 16) & 0x1fff; - x |= ((x & 0x2000) ? 0xffffc000 : 0); - y |= ((y & 0x1000) ? 0xffffe000 : 0); + rgbaint_t poly_color(extradata.poly_color); + int poly_color_a = (extradata.poly_color >> 24) & 0xff; - poly_type = fifo[index] & 0x4000; // 0 = triangle, 1 = quad - last_vertex = fifo[index] & 0x8000; - index++; + int texture_mirror_x = extradata.texture_mirror; + int texture_mirror_y = extradata.texture_mirror; + int texture_x = extradata.texture_x * 8; + int texture_y = extradata.texture_y * 8; + int texture_width = extradata.texture_width; + int texture_height = extradata.texture_height; + int tex_page = extradata.texture_page * 0x40000; + int palette_index = extradata.texture_palette * 256; - z = fifo[index] & 0xffffff00; - brightness = fifo[index] & 0xff; - index++; + int* x_mirror_table = m_tex_mirror_table[texture_mirror_x][texture_width].get(); + int* y_mirror_table = m_tex_mirror_table[texture_mirror_y][texture_height].get(); - if (last_vertex) - { - color = fifo[index++]; - } + bool UseZCompare = (extradata.cmd & 4) != 0; + bool UseFBBlend = (extradata.cmd & 2) == 0; + bool UseFog = extradata.fog_enable; - tu = (fifo[index] >> 16) & 0xffff; - tv = (fifo[index] & 0xffff); - index++; + bool WriteZ = true; + bool UseBilinear = k001006->bilinear_enabled(); - v[vert_num].x = ((float)(x) / 16.0f) + 256.0f; - v[vert_num].y = ((float)(-y) / 16.0f) + 192.0f + 8; - v[vert_num].p[POLY_Z] = *(float*)(&z); - v[vert_num].p[POLY_W] = 1.0f / v[vert_num].p[POLY_Z]; - v[vert_num].p[POLY_U] = tu * v[vert_num].p[POLY_W]; - v[vert_num].p[POLY_V] = tv * v[vert_num].p[POLY_W]; - v[vert_num].p[POLY_BRI] = brightness; - v[vert_num].p[POLY_FOG] = (1.0f / (exp( ((v[vert_num].p[POLY_Z] * fog_density) / m_far_z) * ((v[vert_num].p[POLY_Z] * fog_density) / m_far_z) ))) * 65536.0f; - //v[vert_num].p[POLY_FOG] = (1.0f / (exp( ((v[vert_num].p[POLY_Z] * fog_density) / far_z) ))) * 65536.0f; - if (v[vert_num].p[POLY_FOG] < 0.0f) v[vert_num].p[POLY_FOG] = 0.0f; - if (v[vert_num].p[POLY_FOG] > 65536.0f) v[vert_num].p[POLY_FOG] = 65536.0f; - vert_num++; - } - while (!last_vertex && vert_num < 4); - - tex_y = ((header & 0x400) >> 5) | - ((header & 0x100) >> 4) | - ((header & 0x040) >> 3) | - ((header & 0x010) >> 2) | - ((header & 0x004) >> 1) | - ((header & 0x001) >> 0); - - tex_x = ((header & 0x800) >> 6) | - ((header & 0x200) >> 5) | - ((header & 0x080) >> 4) | - ((header & 0x020) >> 3) | - ((header & 0x008) >> 2) | - ((header & 0x002) >> 1); - - extra.texture_x = tex_x * 8; - extra.texture_y = tex_y * 8; - extra.texture_width = (header >> 23) & 0x7; - extra.texture_height = (header >> 20) & 0x7; - extra.texture_page = (header >> 12) & 0x1f; - extra.texture_palette = (header >> 28) & 0xf; - extra.texture_mirror_x = ((cmd & 0x10) ? 0x1 : 0); - extra.texture_mirror_y = ((cmd & 0x10) ? 0x1 : 0); - extra.color = color; - extra.light_r = m_light_r; extra.light_g = m_light_g; extra.light_b = m_light_b; - extra.ambient_r = m_ambient_r; extra.ambient_g = m_ambient_g; extra.ambient_b = m_ambient_b; - extra.fog_r = m_fog_r; extra.fog_g = m_fog_g; extra.fog_b = m_fog_b; - extra.flags = cmd; - - if ((cmd & 0x20) == 0) // possibly enable flag for gouraud shading (fixes some shading errors) - { - v[0].p[POLY_BRI] = brightness; - v[1].p[POLY_BRI] = brightness; - } + uint32_t texel = 0; + uint32_t texel_alpha = 0; - if (poly_type == 0) // triangle + for (int x = extent.startx; x < extent.stopx; x++) + { + if (z <= zb[x] || !UseZCompare) + { + if (UseTexture) { - if (vert_num == 1) - { - vertex1 = &m_prev_v[2]; - vertex2 = &m_prev_v[3]; - vertex3 = &v[0]; - } - else if (vert_num == 2) - { - vertex1 = &m_prev_v[3]; - vertex2 = &v[0]; - vertex3 = &v[1]; - } - else - { - vertex1 = &v[0]; - vertex2 = &v[1]; - vertex3 = &v[2]; - } + float oow = 1.0f / w; - render_triangle<6>(m_cliprect, rd_scan_tex, *vertex1, *vertex2, *vertex3); + int iu = (int)(u * oow); + int iv = (int)(v * oow); - memcpy(&m_prev_v[1], vertex1, sizeof(vertex_t)); - memcpy(&m_prev_v[2], vertex2, sizeof(vertex_t)); - memcpy(&m_prev_v[3], vertex3, sizeof(vertex_t)); - } - else // quad - { - if (vert_num == 1) + if (!UseBilinear) { - vertex1 = &m_prev_v[1]; - vertex2 = &m_prev_v[2]; - vertex3 = &m_prev_v[3]; - vertex4 = &v[0]; - } - else if (vert_num == 2) - { - vertex1 = &m_prev_v[2]; - vertex2 = &m_prev_v[3]; - vertex3 = &v[0]; - vertex4 = &v[1]; - } - else if (vert_num == 3) - { - vertex1 = &m_prev_v[3]; - vertex2 = &v[0]; - vertex3 = &v[1]; - vertex4 = &v[2]; + int texel_u = texture_x + x_mirror_table[(iu >> 4) & 0x7f]; + int texel_v = texture_y + y_mirror_table[(iv >> 4) & 0x7f]; + + texel = k001006->fetch_texel(tex_page, palette_index, texel_u, texel_v); + texel_alpha = texel >> 24; } else { - vertex1 = &v[0]; - vertex2 = &v[1]; - vertex3 = &v[2]; - vertex4 = &v[3]; - } + // sub-texel bias to avoid seams + iu -= 7; + iv -= 7; - render_triangle<6>(m_cliprect, rd_scan_tex, *vertex1, *vertex2, *vertex3); - render_triangle<6>(m_cliprect, rd_scan_tex, *vertex3, *vertex4, *vertex1); + int ufrac = iu & 0xf; + int vfrac = iv & 0xf; + int texel_u0 = texture_x + x_mirror_table[(iu >> 4) & 0x7f]; + int texel_u1 = texture_x + x_mirror_table[((iu >> 4) + 1) & 0x7f]; + int texel_v0 = texture_y + y_mirror_table[(iv >> 4) & 0x7f]; + int texel_v1 = texture_y + y_mirror_table[((iv >> 4) + 1) & 0x7f]; - memcpy(&m_prev_v[0], vertex1, sizeof(vertex_t)); - memcpy(&m_prev_v[1], vertex2, sizeof(vertex_t)); - memcpy(&m_prev_v[2], vertex3, sizeof(vertex_t)); - memcpy(&m_prev_v[3], vertex4, sizeof(vertex_t)); - } + uint32_t tex00 = k001006->fetch_texel(tex_page, palette_index, texel_u0, texel_v0); + uint32_t tex01 = k001006->fetch_texel(tex_page, palette_index, texel_u1, texel_v0); + uint32_t tex10 = k001006->fetch_texel(tex_page, palette_index, texel_u0, texel_v1); + uint32_t tex11 = k001006->fetch_texel(tex_page, palette_index, texel_u1, texel_v1); - while ((fifo[index] & 0xffffff00) != 0x80000000 && index < m_3dfifo_ptr) - { - k001005_polydata &extra = object_data_alloc(); - int new_verts = 0; + texel = rgbaint_t::bilinear_filter(tex00, tex01, tex10, tex11, ufrac * 16, vfrac * 16); + texel_alpha = tex00 >> 24; + } + } - memcpy(&v[0], &m_prev_v[2], sizeof(vertex_t)); - memcpy(&v[1], &m_prev_v[3], sizeof(vertex_t)); + int idiff = std::clamp((int)(diff), 0, 255); + int ifog = std::clamp((int)(fog), 0, 255); - last_vertex = 0; - vert_num = 2; - do - { - int x, y, z; - int16_t tu, tv; - x = ((fifo[index] >> 0) & 0x3fff); - y = ((fifo[index] >> 16) & 0x1fff); - x |= ((x & 0x2000) ? 0xffffc000 : 0); - y |= ((y & 0x1000) ? 0xffffe000 : 0); + rgbaint_t light_color(extradata.diffuse_light); + light_color.scale_imm_and_clamp(idiff); + light_color.add(ambient_color); + light_color.clamp_to_uint8(); - poly_type = fifo[index] & 0x4000; - last_vertex = fifo[index] & 0x8000; - index++; + if (UseVertexColor) + { + int ir = std::clamp((int)(r), 0, 255); + int ig = std::clamp((int)(g), 0, 255); + int ib = std::clamp((int)(b), 0, 255); + int ia = std::clamp((int)(a), 0, 255); - z = fifo[index] & 0xffffff00; - brightness = fifo[index] & 0xff; - index++; + if (ia != 0) + { + rgbaint_t color(ia, ir, ig, ib); - if (last_vertex) - { - color = fifo[index++]; + if (UseTexture && texel_alpha != 0) + { + color.set(texel); } - tu = (fifo[index] >> 16) & 0xffff; - tv = (fifo[index] >> 0) & 0xffff; - index++; - - v[vert_num].x = ((float)(x) / 16.0f) + 256.0f; - v[vert_num].y = ((float)(-y) / 16.0f) + 192.0f + 8; - v[vert_num].p[POLY_Z] = *(float*)(&z); - v[vert_num].p[POLY_W] = 1.0f / v[vert_num].p[POLY_Z]; - v[vert_num].p[POLY_U] = tu * v[vert_num].p[POLY_W]; - v[vert_num].p[POLY_V] = tv * v[vert_num].p[POLY_W]; - v[vert_num].p[POLY_BRI] = brightness; - v[vert_num].p[POLY_FOG] = (1.0f / (exp( ((v[vert_num].p[POLY_Z] * fog_density) / m_far_z) * ((v[vert_num].p[POLY_Z] * fog_density) / m_far_z) ))) * 65536.0f; - //v[vert_num].p[POLY_FOG] = (1.0f / (exp( ((v[vert_num].p[POLY_Z] * fog_density) / far_z) ))) * 65536.0f; - if (v[vert_num].p[POLY_FOG] < 0.0f) v[vert_num].p[POLY_FOG] = 0.0f; - if (v[vert_num].p[POLY_FOG] > 65536.0f) v[vert_num].p[POLY_FOG] = 65536.0f; - - vert_num++; - new_verts++; - } - while (!last_vertex && vert_num < 4); - - extra.texture_x = tex_x * 8; - extra.texture_y = tex_y * 8; - extra.texture_width = (header >> 23) & 0x7; - extra.texture_height = (header >> 20) & 0x7; - - extra.texture_page = (header >> 12) & 0x1f; - extra.texture_palette = (header >> 28) & 0xf; - - extra.texture_mirror_x = ((cmd & 0x10) ? 0x1 : 0);// & ((header & 0x00400000) ? 0x1 : 0); - extra.texture_mirror_y = ((cmd & 0x10) ? 0x1 : 0);// & ((header & 0x00400000) ? 0x1 : 0); - - extra.color = color; - extra.light_r = m_light_r; extra.light_g = m_light_g; extra.light_b = m_light_b; - extra.ambient_r = m_ambient_r; extra.ambient_g = m_ambient_g; extra.ambient_b = m_ambient_b; - extra.fog_r = m_fog_r; extra.fog_g = m_fog_g; extra.fog_b = m_fog_b; - extra.flags = cmd; - - if ((cmd & 0x20) == 0) // possibly enable flag for gouraud shading (fixes some shading errors) - { - v[0].p[POLY_BRI] = brightness; - v[1].p[POLY_BRI] = brightness; - } + color.scale_and_clamp(light_color); - if (new_verts == 1) - { - render_triangle<6>(m_cliprect, rd_scan_tex, v[0], v[1], v[2]); + if (UseFog) + { + color.blend(fog_color, ifog); + } - memcpy(&m_prev_v[1], &v[0], sizeof(vertex_t)); - memcpy(&m_prev_v[2], &v[1], sizeof(vertex_t)); - memcpy(&m_prev_v[3], &v[2], sizeof(vertex_t)); - } - else if (new_verts == 2) - { - render_triangle<6>(m_cliprect, rd_scan_tex, v[0], v[1], v[2]); - render_triangle<6>(m_cliprect, rd_scan_tex, v[2], v[3], v[0]); + // framebuffer blend + if (UseFBBlend) + { + rgbaint_t fb_color(fb[x]); + color.blend(fb_color, ia); + } - memcpy(&m_prev_v[0], &v[0], sizeof(vertex_t)); - memcpy(&m_prev_v[1], &v[1], sizeof(vertex_t)); - memcpy(&m_prev_v[2], &v[2], sizeof(vertex_t)); - memcpy(&m_prev_v[3], &v[3], sizeof(vertex_t)); + fb[x] = color.to_rgba(); + if (WriteZ) + zb[x] = z; } - }; - } - else if (cmd == 0x80000006 || cmd == 0x80000026 || cmd == 0x80000002 || cmd == 0x80000020 || cmd == 0x80000022) - { - // no texture, Z - - k001005_polydata &extra = object_data_alloc(); - uint32_t color; - int r, g, b, a; - - int last_vertex = 0; - int vert_num = 0; - do - { - int x, y, z; - - x = (fifo[index] >> 0) & 0x3fff; - y = (fifo[index] >> 16) & 0x1fff; - x |= ((x & 0x2000) ? 0xffffc000 : 0); - y |= ((y & 0x1000) ? 0xffffe000 : 0); - - poly_type = fifo[index] & 0x4000; // 0 = triangle, 1 = quad - last_vertex = fifo[index] & 0x8000; - index++; - - z = fifo[index] & 0xffffff00; - brightness = fifo[index] & 0xff; - index++; - - v[vert_num].x = ((float)(x) / 16.0f) + 256.0f; - v[vert_num].y = ((float)(-y) / 16.0f) + 192.0f + 8; - v[vert_num].p[POLY_Z] = *(float*)(&z); - v[vert_num].p[POLY_BRI] = brightness; - v[vert_num].p[POLY_FOG] = (1.0f / (exp( ((v[vert_num].p[POLY_Z] * fog_density) / m_far_z) * ((v[vert_num].p[POLY_Z] * fog_density) / m_far_z) ))) * 65536.0f; - //v[vert_num].p[POLY_FOG] = (1.0f / (exp( ((v[vert_num].p[POLY_Z] * fog_density) / far_z) ))) * 65536.0f; - if (v[vert_num].p[POLY_FOG] < 0.0f) v[vert_num].p[POLY_FOG] = 0.0f; - if (v[vert_num].p[POLY_FOG] > 65536.0f) v[vert_num].p[POLY_FOG] = 65536.0f; - vert_num++; - } - while (!last_vertex && vert_num < 4); - - r = (fifo[index] >> 0) & 0xff; - g = (fifo[index] >> 8) & 0xff; - b = (fifo[index] >> 16) & 0xff; - a = (fifo[index] >> 24) & 0xff; - color = (a << 24) | (r << 16) | (g << 8) | (b); - index++; - - extra.color = color; - extra.light_r = m_light_r; extra.light_g = m_light_g; extra.light_b = m_light_b; - extra.ambient_r = m_ambient_r; extra.ambient_g = m_ambient_g; extra.ambient_b = m_ambient_b; - extra.fog_r = m_fog_r; extra.fog_g = m_fog_g; extra.fog_b = m_fog_b; - extra.flags = cmd; - - if ((cmd & 0x20) == 0) // possibly enable flag for gouraud shading (fixes some shading errors) - { - v[0].p[POLY_BRI] = brightness; - v[1].p[POLY_BRI] = brightness; } - - if (poly_type == 0) // triangle + else { - if (vert_num == 1) - { - vertex1 = &m_prev_v[2]; - vertex2 = &m_prev_v[3]; - vertex3 = &v[0]; - } - else if (vert_num == 2) + if (UseTexture) { - vertex1 = &m_prev_v[3]; - vertex2 = &v[0]; - vertex3 = &v[1]; + if (texel_alpha != 0) + { + rgbaint_t texel_color(texel); + texel_color.scale_and_clamp(light_color); + + // TODO: is there a toggle for texture blending? cmd bit 0x02 doesn't seem like it + if (UseBilinear && texel_alpha < 0xff) + { + rgbaint_t fb_color(fb[x]); + texel_color.blend(fb_color, texel_alpha); + } + + if (UseFog) + { + texel_color.blend(fog_color, ifog); + } + + if (UseFBBlend) + { + rgbaint_t fb_color(fb[x]); + texel_color.blend(fb_color, poly_color_a); + } + + fb[x] = texel_color.to_rgba(); + if (WriteZ) + zb[x] = z; + } } else { - vertex1 = &v[0]; - vertex2 = &v[1]; - vertex3 = &v[2]; + //if (poly_color_a != 0) + { + rgbaint_t color(extradata.poly_color); + color.scale_and_clamp(light_color); + + if (UseFog) + { + color.blend(fog_color, ifog); + } + + // framebuffer blend + if (UseFBBlend) + { + rgbaint_t fb_color(fb[x]); + color.blend(fb_color, poly_color_a); + } + + fb[x] = color.to_rgba(); + if (WriteZ) + zb[x] = z; + } } - - render_triangle<3>(m_cliprect, rd_scan, *vertex1, *vertex2, *vertex3); - - memcpy(&m_prev_v[1], vertex1, sizeof(vertex_t)); - memcpy(&m_prev_v[2], vertex2, sizeof(vertex_t)); - memcpy(&m_prev_v[3], vertex3, sizeof(vertex_t)); } - else // quad - { - if (vert_num == 1) - { - vertex1 = &m_prev_v[1]; - vertex2 = &m_prev_v[2]; - vertex3 = &m_prev_v[3]; - vertex4 = &v[0]; - } - else if (vert_num == 2) - { - vertex1 = &m_prev_v[2]; - vertex2 = &m_prev_v[3]; - vertex3 = &v[0]; - vertex4 = &v[1]; - } - else if (vert_num == 3) - { - vertex1 = &m_prev_v[3]; - vertex2 = &v[0]; - vertex3 = &v[1]; - vertex4 = &v[2]; - } - else - { - vertex1 = &v[0]; - vertex2 = &v[1]; - vertex3 = &v[2]; - vertex4 = &v[3]; - } - render_triangle<3>(m_cliprect, rd_scan, *vertex1, *vertex2, *vertex3); - render_triangle<3>(m_cliprect, rd_scan, *vertex3, *vertex4, *vertex1); + } - memcpy(&m_prev_v[0], vertex1, sizeof(vertex_t)); - memcpy(&m_prev_v[1], vertex2, sizeof(vertex_t)); - memcpy(&m_prev_v[2], vertex3, sizeof(vertex_t)); - memcpy(&m_prev_v[3], vertex4, sizeof(vertex_t)); - } + z += dz; + diff += ddiff; + fog += dfog; - while ((fifo[index] & 0xffffff00) != 0x80000000 && index < m_3dfifo_ptr) - { - int new_verts = 0; + if (UseVertexColor) + { + r += dr; + g += dg; + b += db; + a += da; + } - memcpy(&v[0], &m_prev_v[2], sizeof(vertex_t)); - memcpy(&v[1], &m_prev_v[3], sizeof(vertex_t)); + if (UseTexture) + { + u += du; + v += dv; + w += dw; + } + } +} - last_vertex = 0; - vert_num = 2; - do - { - int x, y, z; - x = ((fifo[index] >> 0) & 0x3fff); - y = ((fifo[index] >> 16) & 0x1fff); - x |= ((x & 0x2000) ? 0xffffc000 : 0); - y |= ((y & 0x1000) ? 0xffffe000 : 0); +/* + Command + 0x00: xxxxxxxx xxxxxxxx xxxxxxx- -------- 0x80000000 (exact number of bits unknown) + 0x00: -------- -------- -------x -------- 0 = per-poly color, 1 = per-vertex color + 0x00: -------- -------- -------- x------- ? Texture related + 0x00: -------- -------- -------- -x------ Unused? + 0x00: -------- -------- -------- --x----- 1 = enable smooth shading? + 0x00: -------- -------- -------- ---x---- 1 = texture mirroring + 0x00: -------- -------- -------- ----x--- ? Texture related + 0x00: -------- -------- -------- -----x-- 1 = enable Z-buffer read + 0x00: -------- -------- -------- ------x- 0 = blend enabled, 1 = disabled + 0x00: -------- -------- -------- -------x 0 = per-vertex Z, 1 = per-poly Z (0x80000121 seems like an exception) + + Texture header + 0x01: -xxx---- -------- -------- -------- Texture palette + 0x01: ----xx-- -------- -------- -------- Unknown flags, set by commands 0x7b...0x7e. Used mostly on polygons further away from camera. Some kind of depth-based effect? + 0x01: ------xx x------- -------- -------- Texture width / 8 - 1 + 0x01: -------- -xxx---- -------- -------- Texture height / 8 - 1 + 0x01: -------- -------x xxxx---- -------- Texture page + 0x01: -------- -------- ----x-x- x-x-x-x- Texture X / 8 + 0x01: -------- -------- -----x-x -x-x-x-x Texture Y / 8 +*/ - poly_type = fifo[index] & 0x4000; - last_vertex = fifo[index] & 0x8000; - index++; +int k001005_renderer::parse_polygon(int index, uint32_t cmd) +{ + render_delegate rd_scan_tex = render_delegate(&k001005_renderer::draw_scanline_generic<true, false>, this); + render_delegate rd_scan_vertex_color = render_delegate(&k001005_renderer::draw_scanline_generic<false, true>, this); + render_delegate rd_scan_vertex_color_tex = render_delegate(&k001005_renderer::draw_scanline_generic<true, true>, this); + render_delegate rd_scan_color = render_delegate(&k001005_renderer::draw_scanline_generic<false, false>, this); - z = fifo[index] & 0xffffff00; - brightness = fifo[index] & 0xff; - index++; + int viewport_min_x = std::clamp(256 + m_viewport_min_x + m_viewport_center_x, m_cliprect.min_x, m_cliprect.max_x); + int viewport_max_x = std::clamp(256 + m_viewport_max_x + m_viewport_center_x + 1, m_cliprect.min_x, m_cliprect.max_x); + int viewport_min_y = std::clamp(200 + m_viewport_min_y - m_viewport_center_y, m_cliprect.min_y, m_cliprect.max_y); + int viewport_max_y = std::clamp(200 + m_viewport_max_y - m_viewport_center_y + 1, m_cliprect.min_y, m_cliprect.max_y); - v[vert_num].x = ((float)(x) / 16.0f) + 256.0f; - v[vert_num].y = ((float)(-y) / 16.0f) + 192.0f + 8; - v[vert_num].p[POLY_Z] = *(float*)(&z); - v[vert_num].p[POLY_BRI] = brightness; - v[vert_num].p[POLY_FOG] = (1.0f / (exp( ((v[vert_num].p[POLY_Z] * fog_density) / m_far_z) * ((v[vert_num].p[POLY_Z] * fog_density) / m_far_z) ))) * 65536.0f; - //v[vert_num].p[POLY_FOG] = (1.0f / (exp( ((v[vert_num].p[POLY_Z] * fog_density) / far_z) ))) * 65536.0f; - if (v[vert_num].p[POLY_FOG] < 0.0f) v[vert_num].p[POLY_FOG] = 0.0f; - if (v[vert_num].p[POLY_FOG] > 65536.0f) v[vert_num].p[POLY_FOG] = 65536.0f; - - vert_num++; - new_verts++; - } - while (!last_vertex && vert_num < 4); + rectangle cliprect(viewport_min_x, viewport_max_x, viewport_min_y, viewport_max_y); + - r = (fifo[index] >> 0) & 0xff; - g = (fifo[index] >> 8) & 0xff; - b = (fifo[index] >> 16) & 0xff; - a = (fifo[index] >> 24) & 0xff; - color = (a << 24) | (r << 16) | (g << 8) | (b); - index++; + int start_index = index; - extra.color = color; - extra.light_r = m_light_r; extra.light_g = m_light_g; extra.light_b = m_light_b; - extra.ambient_r = m_ambient_r; extra.ambient_g = m_ambient_g; extra.ambient_b = m_ambient_b; - extra.fog_r = m_fog_r; extra.fog_g = m_fog_g; extra.fog_b = m_fog_b; - extra.flags = cmd; + uint32_t* fifo = m_3dfifo.get(); - if ((cmd & 0x20) == 0) // possibly enable flag for gouraud shading (fixes some shading errors) - { - v[0].p[POLY_BRI] = brightness; - v[1].p[POLY_BRI] = brightness; - } + bool has_texture = (cmd & 0x18) != 0; + bool has_vertex_color = (cmd & 0x100) != 0; + bool has_vertex_z = !(cmd & 1) || has_vertex_color; // command 0x121 breaks the logic here, maybe vertex color enforces vertex z too? - if (new_verts == 1) - { - render_triangle<3>(m_cliprect, rd_scan, v[0], v[1], v[2]); + uint32_t texture_x = 0; + uint32_t texture_y = 0; + uint32_t texture_width = 0; + uint32_t texture_height = 0; + uint32_t texture_page = 0; + uint32_t texture_palette = 0; - memcpy(&m_prev_v[1], &v[0], sizeof(vertex_t)); - memcpy(&m_prev_v[2], &v[1], sizeof(vertex_t)); - memcpy(&m_prev_v[3], &v[2], sizeof(vertex_t)); - } - else if (new_verts == 2) - { - render_triangle<3>(m_cliprect, rd_scan, v[0], v[1], v[2]); - render_triangle<3>(m_cliprect, rd_scan, v[2], v[3], v[0]); + uint32_t tex_header = 0; - memcpy(&m_prev_v[0], &v[0], sizeof(vertex_t)); - memcpy(&m_prev_v[1], &v[1], sizeof(vertex_t)); - memcpy(&m_prev_v[2], &v[2], sizeof(vertex_t)); - memcpy(&m_prev_v[3], &v[3], sizeof(vertex_t)); - } - } - } - else if (cmd == 0x80000003 || cmd == 0x80000001) - { - // no texture, no Z + // texture header - only for textured polys + if (has_texture) + { + tex_header = fifo[index++]; - k001005_polydata &extra = object_data_alloc(); - int r, g, b, a; - uint32_t color; + texture_x = (((tex_header >> 6) & 0x20) | ((tex_header >> 5) & 0x10) | ((tex_header >> 4) & 0x8) | + ((tex_header >> 3) & 0x4) | ((tex_header >> 2) & 0x2) | ((tex_header >> 1) & 0x1)); - int last_vertex = 0; - int vert_num = 0; - do - { - int x, y; + texture_y = (((tex_header >> 5) & 0x20) | ((tex_header >> 4) & 0x10) | ((tex_header >> 3) & 0x8) | + ((tex_header >> 2) & 0x4) | ((tex_header >> 1) & 0x2) | (tex_header & 0x1)); - x = ((fifo[index] >> 0) & 0x3fff); - y = ((fifo[index] >> 16) & 0x1fff); - x |= ((x & 0x2000) ? 0xffffc000 : 0); - y |= ((y & 0x1000) ? 0xffffe000 : 0); + texture_width = (tex_header >> 23) & 0x7; + texture_height = (tex_header >> 20) & 0x7; + texture_page = (tex_header >> 12) & 0x1f; + texture_palette = (tex_header >> 28) & 0x7; + } - poly_type = fifo[index] & 0x4000; - last_vertex = fifo[index] & 0x8000; - index++; + while ((fifo[index] & 0xffff0000) != 0x80000000 && index < m_3dfifo_ptr) + { + k001005_polydata& extra = object_data_alloc(); - v[vert_num].x = ((float)(x) / 16.0f) + 256.0f; - v[vert_num].y = ((float)(-y) / 16.0f) + 192.0f + 8; - vert_num++; - } - while (!last_vertex && vert_num < 4); + bool last_vertex = false; + bool is_quad = false; - // unknown word - index++; + uint32_t polygon_color = 0; + float polygon_z = 0.0f; + uint32_t polygon_diffuse = 0; - r = (fifo[index] >> 0) & 0xff; - g = (fifo[index] >> 8) & 0xff; - b = (fifo[index] >> 16) & 0xff; - a = (fifo[index] >> 24) & 0xff; - color = (a << 24) | (r << 16) | (g << 8) | (b); - index++; + int num_new_verts = 0; - extra.color = color; - extra.flags = cmd; + do + { + // X/Y coords, flags - all polys have this + // ------------------------------------------------------------------------- + int x = fifo[index] & 0x3fff; + x |= ((x & 0x2000) ? 0xffffc000 : 0); + int y = (fifo[index] >> 16) & 0x1fff; + y |= ((y & 0x1000) ? 0xffffe000 : 0); + + m_vertexb[m_vertexb_ptr].x = ((float)(x) / 16.0f) + 256.0f; + m_vertexb[m_vertexb_ptr].y = ((float)(-y) / 16.0f) + 200.0f; + + is_quad = (fifo[index] & 0x4000) != 0; + last_vertex = (fifo[index] & 0x8000) != 0; + index++; - if (poly_type == 0) + // Z + diffuse intensity - if Z enabled + // ------------------------------------------------------------------------- + if (has_vertex_z) { - render_triangle<0>(m_cliprect, rd_scan_2d, v[0], v[1], v[2]); + uint32_t z = fifo[index] & 0xffffff00; // 32-bit float with low 8-bits of mantissa masked out + int diffuse = fifo[index] & 0xff; + index++; + + m_vertexb[m_vertexb_ptr].p[POLY_Z] = u2f(z); + m_vertexb[m_vertexb_ptr].p[POLY_DIFF] = diffuse; + m_vertexb[m_vertexb_ptr].p[POLY_W] = 1.0f / m_vertexb[m_vertexb_ptr].p[POLY_Z]; } else { - render_triangle<0>(m_cliprect, rd_scan_2d, v[0], v[1], v[2]); - render_triangle<0>(m_cliprect, rd_scan_2d, v[2], v[3], v[0]); + m_vertexb[m_vertexb_ptr].p[POLY_W] = 1.0f; } - } - else if (cmd == 0x8000008b) - { - // texture, no Z - int tex_x, tex_y; - k001005_polydata &extra = object_data_alloc(); - int r, g, b, a; - uint32_t color = 0; - - uint32_t header = fifo[index++]; - - int last_vertex = 0; - int vert_num = 0; - do + // textured polygons have a polygon color field after last vertex data, but before the last UV coords + // ------------------------------------------------------------------------- + if (last_vertex && has_texture) { - int x, y; - int16_t tu, tv; - - x = ((fifo[index] >> 0) & 0x3fff); - y = ((fifo[index] >> 16) & 0x1fff); - x |= ((x & 0x2000) ? 0xffffc000 : 0); - y |= ((y & 0x1000) ? 0xffffe000 : 0); - - poly_type = fifo[index] & 0x4000; - last_vertex = fifo[index] & 0x8000; - index++; - - if (last_vertex) + // polygon Z comes before the last UV coords for textured polygons + if (!has_vertex_z) { - // unknown word + uint32_t z = (fifo[index] & 0x07ffff00) | 0x48000000; // like fog values, these seem to be missing the 4 upper bits of exponent + polygon_diffuse = fifo[index] & 0xff; index++; - - color = fifo[index++]; + polygon_z = u2f(z); } - tu = (fifo[index] >> 16) & 0xffff; - tv = (fifo[index] & 0xffff); - index++; - - v[vert_num].x = ((float)(x) / 16.0f) + 256.0f; - v[vert_num].y = ((float)(-y) / 16.0f) + 192.0f + 8; - v[vert_num].p[POLY_U] = tu; - v[vert_num].p[POLY_V] = tv; - vert_num++; - } - while (!last_vertex && vert_num < 4); - - r = (color >> 0) & 0xff; - g = (color >> 8) & 0xff; - b = (color >> 16) & 0xff; - a = (color >> 24) & 0xff; - extra.color = (a << 24) | (r << 16) | (g << 8) | (b); - extra.flags = cmd; - - tex_y = ((header & 0x400) >> 5) | - ((header & 0x100) >> 4) | - ((header & 0x040) >> 3) | - ((header & 0x010) >> 2) | - ((header & 0x004) >> 1) | - ((header & 0x001) >> 0); - - tex_x = ((header & 0x800) >> 6) | - ((header & 0x200) >> 5) | - ((header & 0x080) >> 4) | - ((header & 0x020) >> 3) | - ((header & 0x008) >> 2) | - ((header & 0x002) >> 1); - - extra.texture_x = tex_x * 8; - extra.texture_y = tex_y * 8; - extra.texture_width = (header >> 23) & 0x7; - extra.texture_height = (header >> 20) & 0x7; - - extra.texture_page = (header >> 12) & 0x1f; - extra.texture_palette = (header >> 28) & 0xf; - - extra.texture_mirror_x = ((cmd & 0x10) ? 0x1 : 0); - extra.texture_mirror_y = ((cmd & 0x10) ? 0x1 : 0); - - if (poly_type == 0) - { - render_triangle<5>(m_cliprect, rd_scan_tex2d, v[0], v[1], v[2]); - } - else - { - render_triangle<5>(m_cliprect, rd_scan_tex2d, v[0], v[1], v[2]); - render_triangle<5>(m_cliprect, rd_scan_tex2d, v[2], v[3], v[0]); + if (!has_vertex_color) + { + polygon_color = fifo[index]; + index++; + } } - } - else if (cmd == 0x80000106 || cmd == 0x80000121 || cmd == 0x80000126) - { - // no texture, color gouraud, Z - k001005_polydata &extra = object_data_alloc(); - uint32_t color; - - int last_vertex = 0; - int vert_num = 0; - do + // vertex color + if (has_vertex_color) { - int x, y, z; - - x = ((fifo[index] >> 0) & 0x3fff); - y = ((fifo[index] >> 16) & 0x1fff); - x |= ((x & 0x2000) ? 0xffffc000 : 0); - y |= ((y & 0x1000) ? 0xffffe000 : 0); - - poly_type = fifo[index] & 0x4000; - last_vertex = fifo[index] & 0x8000; + uint32_t vertex_color = fifo[index]; index++; - z = fifo[index] & 0xffffff00; - brightness = fifo[index] & 0xff; - index++; + m_vertexb[m_vertexb_ptr].p[POLY_A] = (vertex_color >> 24) & 0xff; + m_vertexb[m_vertexb_ptr].p[POLY_B] = (vertex_color >> 16) & 0xff; + m_vertexb[m_vertexb_ptr].p[POLY_G] = (vertex_color >> 8) & 0xff; + m_vertexb[m_vertexb_ptr].p[POLY_R] = vertex_color & 0xff; + + } - color = fifo[index]; + // UV coords - only for texture polys + if (has_texture) + { + int32_t tu = (int16_t)(fifo[index] >> 16); + int32_t tv = (int16_t)(fifo[index] & 0xffff); index++; - v[vert_num].x = ((float)(x) / 16.0f) + 256.0f; - v[vert_num].y = ((float)(-y) / 16.0f) + 192.0f + 8; - v[vert_num].p[POLY_Z] = *(float*)(&z); - v[vert_num].p[POLY_B] = (color >> 16) & 0xff; - v[vert_num].p[POLY_G] = (color >> 8) & 0xff; - v[vert_num].p[POLY_R] = color & 0xff; - v[vert_num].p[POLY_A] = (color >> 24) & 0xff; - vert_num++; + m_vertexb[m_vertexb_ptr].p[POLY_U] = (float)(tu) * m_vertexb[m_vertexb_ptr].p[POLY_W]; + m_vertexb[m_vertexb_ptr].p[POLY_V] = (float)(tv) * m_vertexb[m_vertexb_ptr].p[POLY_W]; } - while (!last_vertex && vert_num < 4); - - extra.color = color; - extra.flags = cmd; - if (poly_type == 0) + // fog + if (m_reg_fog_start == 0xffff) { - render_triangle<6>(m_cliprect, rd_scan_gour_blend, v[0], v[1], v[2]); + // max fog start value means fog is off + m_vertexb[m_vertexb_ptr].p[POLY_FOG] = 0.0f; } else { - render_triangle<6>(m_cliprect, rd_scan_gour_blend, v[0], v[1], v[2]); - render_triangle<6>(m_cliprect, rd_scan_gour_blend, v[2], v[3], v[0]); + float fog_factor = (m_fog_end_z - m_vertexb[m_vertexb_ptr].p[POLY_Z]) / (m_fog_end_z - m_fog_start_z); + m_vertexb[m_vertexb_ptr].p[POLY_FOG] = fog_factor * 255.0f; } - // TODO: can this poly type form strips? + num_new_verts++; + m_vertexb_ptr = (m_vertexb_ptr + 1) & 3; } - else if (cmd == 0x8000010e) - { - // texture, color gouraud, Z (color gouraud is shown where texture is transparent, used by midnrun/windheat CG board test) - int tex_x, tex_y; - uint32_t color = 0; - k001005_polydata& extra = object_data_alloc(); + while (!last_vertex && num_new_verts < 4); - uint32_t header = fifo[index++]; - - int last_vertex = 0; - int vert_num = 0; - do + // for non-textured polygons, polygon color comes after vertex data + if (!has_texture) + { + // polygon Z + if (!has_vertex_z) { - int x, y, z; - int16_t tu, tv; - - x = (fifo[index] >> 0) & 0x3fff; - y = (fifo[index] >> 16) & 0x1fff; - x |= ((x & 0x2000) ? 0xffffc000 : 0); - y |= ((y & 0x1000) ? 0xffffe000 : 0); - - poly_type = fifo[index] & 0x4000; // 0 = triangle, 1 = quad - last_vertex = fifo[index] & 0x8000; - index++; - - z = fifo[index] & 0xffffff00; - brightness = fifo[index] & 0xff; + uint32_t z = (fifo[index] & 0x07ffff00) | 0x48000000; // like fog values, these seem to be missing the 4 upper bits of exponent + polygon_diffuse = fifo[index] & 0xff; index++; - color = fifo[index]; - index++; - - tu = (fifo[index] >> 16) & 0xffff; - tv = (fifo[index] & 0xffff); - index++; - - v[vert_num].x = ((float)(x) / 16.0f) + 256.0f; - v[vert_num].y = ((float)(-y) / 16.0f) + 192.0f + 8; - v[vert_num].p[POLY_Z] = *(float*)(&z); - v[vert_num].p[POLY_W] = 1.0f / v[vert_num].p[POLY_Z]; - v[vert_num].p[POLY_U] = tu * v[vert_num].p[POLY_W]; - v[vert_num].p[POLY_V] = tv * v[vert_num].p[POLY_W]; - v[vert_num].p[POLY_BRI] = brightness; - v[vert_num].p[POLY_FOG] = (1.0f / (exp(((v[vert_num].p[POLY_Z] * fog_density) / m_far_z) * ((v[vert_num].p[POLY_Z] * fog_density) / m_far_z)))) * 65536.0f; - //v[vert_num].p[POLY_FOG] = (1.0f / (exp( ((v[vert_num].p[POLY_Z] * fog_density) / far_z) ))) * 65536.0f; - if (v[vert_num].p[POLY_FOG] < 0.0f) v[vert_num].p[POLY_FOG] = 0.0f; - if (v[vert_num].p[POLY_FOG] > 65536.0f) v[vert_num].p[POLY_FOG] = 65536.0f; - v[vert_num].p[POLY_ALTB] = (color >> 16) & 0xff; - v[vert_num].p[POLY_ALTG] = (color >> 8) & 0xff; - v[vert_num].p[POLY_ALTR] = color & 0xff; - v[vert_num].p[POLY_ALTA] = (color >> 24) & 0xff; - vert_num++; - } while (!last_vertex && vert_num < 4); - - tex_y = ((header & 0x400) >> 5) | - ((header & 0x100) >> 4) | - ((header & 0x040) >> 3) | - ((header & 0x010) >> 2) | - ((header & 0x004) >> 1) | - ((header & 0x001) >> 0); - - tex_x = ((header & 0x800) >> 6) | - ((header & 0x200) >> 5) | - ((header & 0x080) >> 4) | - ((header & 0x020) >> 3) | - ((header & 0x008) >> 2) | - ((header & 0x002) >> 1); - - extra.texture_x = tex_x * 8; - extra.texture_y = tex_y * 8; - extra.texture_width = (header >> 23) & 0x7; - extra.texture_height = (header >> 20) & 0x7; - extra.texture_page = (header >> 12) & 0x1f; - extra.texture_palette = (header >> 28) & 0xf; - extra.texture_mirror_x = ((cmd & 0x10) ? 0x1 : 0); - extra.texture_mirror_y = ((cmd & 0x10) ? 0x1 : 0); - extra.color = 0xffffffff; - extra.light_r = m_light_r; extra.light_g = m_light_g; extra.light_b = m_light_b; - extra.ambient_r = m_ambient_r; extra.ambient_g = m_ambient_g; extra.ambient_b = m_ambient_b; - extra.fog_r = m_fog_r; extra.fog_g = m_fog_g; extra.fog_b = m_fog_b; - extra.flags = cmd; - - if ((cmd & 0x20) == 0) // possibly enable flag for gouraud shading (fixes some shading errors) - { - v[0].p[POLY_BRI] = brightness; - v[1].p[POLY_BRI] = brightness; + polygon_z = u2f(z); } - if (poly_type == 0) // triangle + // polygon color + if (!has_vertex_color) { - if (vert_num == 1) - { - vertex1 = &m_prev_v[2]; - vertex2 = &m_prev_v[3]; - vertex3 = &v[0]; - } - else if (vert_num == 2) - { - vertex1 = &m_prev_v[3]; - vertex2 = &v[0]; - vertex3 = &v[1]; - } - else - { - vertex1 = &v[0]; - vertex2 = &v[1]; - vertex3 = &v[2]; - } - - render_triangle<10>(m_cliprect, rd_scan_tex_gouraud, *vertex1, *vertex2, *vertex3); - - memcpy(&m_prev_v[1], vertex1, sizeof(vertex_t)); - memcpy(&m_prev_v[2], vertex2, sizeof(vertex_t)); - memcpy(&m_prev_v[3], vertex3, sizeof(vertex_t)); - } - else // quad - { - if (vert_num == 1) - { - vertex1 = &m_prev_v[1]; - vertex2 = &m_prev_v[2]; - vertex3 = &m_prev_v[3]; - vertex4 = &v[0]; - } - else if (vert_num == 2) - { - vertex1 = &m_prev_v[2]; - vertex2 = &m_prev_v[3]; - vertex3 = &v[0]; - vertex4 = &v[1]; - } - else if (vert_num == 3) - { - vertex1 = &m_prev_v[3]; - vertex2 = &v[0]; - vertex3 = &v[1]; - vertex4 = &v[2]; - } - else - { - vertex1 = &v[0]; - vertex2 = &v[1]; - vertex3 = &v[2]; - vertex4 = &v[3]; - } - - render_triangle<10>(m_cliprect, rd_scan_tex_gouraud, *vertex1, *vertex2, *vertex3); - render_triangle<10>(m_cliprect, rd_scan_tex_gouraud, *vertex3, *vertex4, *vertex1); - - memcpy(&m_prev_v[0], vertex1, sizeof(vertex_t)); - memcpy(&m_prev_v[1], vertex2, sizeof(vertex_t)); - memcpy(&m_prev_v[2], vertex3, sizeof(vertex_t)); - memcpy(&m_prev_v[3], vertex4, sizeof(vertex_t)); + polygon_color = fifo[index]; + index++; } } - else if (cmd == 0x80000000) - { - } - else if (cmd == 0x80000018) - { - } - else if ((cmd & 0xffff0000) == 0x80000000) - { - /* - osd_printf_debug("Unknown polygon type %08X:\n", fifo[index-1]); - for (int i=0; i < 0x20; i++) - { - osd_printf_debug(" %02X: %08X\n", i, fifo[index+i]); - } - osd_printf_debug("\n"); - */ - printf("Unknown polygon type %08X:\n", fifo[index-1]); - for (int i=0; i < 0x20; i++) + // apply constant Z to all verts if needed + if (!has_vertex_z) + { + for (auto j = 0; j < 4; j++) { - printf(" %02X: %08X\n", i, fifo[index+i]); + m_vertexb[j].p[POLY_Z] = polygon_z; + m_vertexb[j].p[POLY_DIFF] = polygon_diffuse; } - printf("\n"); } - else - { - } - } - while (index < m_3dfifo_ptr); - -#if LOG_POLY_FIFO - printf("\nrender %d\n", K001005_3d_fifo_ptr); - printf("------------------------------------\n"); -#endif - - m_3dfifo_ptr = 0; - wait(); -} - - -void k001005_renderer::draw_scanline_2d(int32_t scanline, const extent_t &extent, const k001005_polydata &extradata, int threadid) -{ - uint32_t *const fb = &m_fb[m_fb_page]->pix(scanline); - float *const zb = (float*)&m_zb->pix(scanline); - uint32_t color = extradata.color; - - for (int x = extent.startx; x < extent.stopx; x++) - { - if (color & 0xff000000) - { - fb[x] = color; - zb[x] = FLT_MAX; // FIXME - } - } -} - -void k001005_renderer::draw_scanline_2d_tex(int32_t scanline, const extent_t &extent, const k001005_polydata &extradata, int threadid) -{ - // int pal_chip = (extradata.texture_palette & 0x8) ? 1 : 0; - k001006_device *k001006 = downcast<k001006_device*>(m_k001006); - - int tex_page = extradata.texture_page * 0x40000; - int palette_index = (extradata.texture_palette & 0x7) * 256; - float u = extent.param[POLY_U].start; - float v = extent.param[POLY_V].start; - float du = extent.param[POLY_U].dpdx; - float dv = extent.param[POLY_V].dpdx; - uint32_t *const fb = &m_fb[m_fb_page]->pix(scanline); - float *const zb = (float*)&m_zb->pix(scanline); - uint32_t color = extradata.color; - int texture_mirror_x = extradata.texture_mirror_x; - int texture_mirror_y = extradata.texture_mirror_y; - int texture_x = extradata.texture_x; - int texture_y = extradata.texture_y; - int texture_width = extradata.texture_width; - int texture_height = extradata.texture_height; - - int *x_mirror_table = m_tex_mirror_table[texture_mirror_x][texture_width].get(); - int *y_mirror_table = m_tex_mirror_table[texture_mirror_y][texture_height].get(); - - for (int x = extent.startx; x < extent.stopx; x++) - { - int iu = (int)(u * 0.0625f); - int iv = (int)(v * 0.0625f); - int iiv, iiu; + extra.texture_x = texture_x; + extra.texture_y = texture_y; + extra.texture_width = texture_width; + extra.texture_height = texture_height; + extra.texture_page = texture_page; + extra.texture_palette = texture_palette; + extra.texture_mirror = (cmd & 0x10); + extra.diffuse_light = rgb_t(m_light_r, m_light_g, m_light_b); + extra.ambient_light = rgb_t(m_ambient_r, m_ambient_g, m_ambient_b); + extra.fog_color = rgb_t(m_fog_r, m_fog_g, m_fog_b); + extra.fog_enable = m_reg_fog_start != 0xffff; + extra.cmd = cmd; + + extra.poly_color = rgb_t((polygon_color >> 24) & 0xff, polygon_color & 0xff, (polygon_color >> 8) & 0xff, (polygon_color >> 16) & 0xff); + + + // If 4 new vertices were found, but no last vertex tag - we're reading garbage. + // Midnrun writes garbage after a 0x80000003 command. The data comes directly from the display list, so it seems intentional. + if (num_new_verts >= 4 && !last_vertex) + break; - iiu = texture_x + x_mirror_table[iu & 0x7f]; - iiv = texture_y + y_mirror_table[iv & 0x7f]; - color = k001006->fetch_texel(tex_page, palette_index, iiu, iiv); + // The vertex buffer is a 4-entry circular buffer. + // Each polygon has at least one new vertex. 0-3 vertices are reused based on how many new vertices were inserted. + int v0 = (m_vertexb_ptr - 4) & 3; + int v1 = (m_vertexb_ptr - 3) & 3; + int v2 = (m_vertexb_ptr - 2) & 3; + int v3 = (m_vertexb_ptr - 1) & 3; - if (color & 0xff000000) + + // This fixes shading issues in the Konami logo in Solar Assault. + // Some triangle strips have different shading values compared to reused vertices, causing unintended smooth shading. + // This ensures all vertices have the same shading value. + // Bit 0x20 could be a select between flat shading and gouraud shading. + if ((cmd & 0x20) == 0 && num_new_verts < 3) { - fb[x] = color; - zb[x] = FLT_MAX; // FIXME + int last_diffuse = m_vertexb[v3].p[POLY_DIFF]; + m_vertexb[v0].p[POLY_DIFF] = last_diffuse; + m_vertexb[v1].p[POLY_DIFF] = last_diffuse; + m_vertexb[v2].p[POLY_DIFF] = last_diffuse; } - u += du; - v += dv; - } -} - -void k001005_renderer::draw_scanline(int32_t scanline, const extent_t &extent, const k001005_polydata &extradata, int threadid) -{ - float z = extent.param[POLY_Z].start; - float dz = extent.param[POLY_Z].dpdx; - float bri = extent.param[POLY_BRI].start; - float dbri = extent.param[POLY_BRI].dpdx; - float fog = extent.param[POLY_FOG].start; - float dfog = extent.param[POLY_FOG].dpdx; - uint32_t *const fb = &m_fb[m_fb_page]->pix(scanline); - float *const zb = (float*)&m_zb->pix(scanline); - uint32_t color = extradata.color; - - int poly_light_r = extradata.light_r + extradata.ambient_r; - int poly_light_g = extradata.light_g + extradata.ambient_g; - int poly_light_b = extradata.light_b + extradata.ambient_b; - if (poly_light_r > 255) poly_light_r = 255; - if (poly_light_g > 255) poly_light_g = 255; - if (poly_light_b > 255) poly_light_b = 255; - int poly_fog_r = extradata.fog_r; - int poly_fog_g = extradata.fog_g; - int poly_fog_b = extradata.fog_b; - - for (int x = extent.startx; x < extent.stopx; x++) - { - int ibri = (int)(bri); - int ifog = (int)(fog); - - if (ibri < 0) ibri = 0; - if (ibri > 255) ibri = 255; - if (ifog < 0) ifog = 0; - if (ifog > 65536) ifog = 65536; - - if (z <= zb[x]) + // No texture, constant color: Z, Fog, Diffuse + // Texture, constant color: Z, Fog, Diffuse, U, V, W + // Per-vertex color: Z, Fog, Diffuse, U, V, W, R, G, B, A + if (is_quad) { - if (color & 0xff000000) + if (has_vertex_color) + { + render_triangle<10>(cliprect, has_texture ? rd_scan_vertex_color_tex : rd_scan_vertex_color, m_vertexb[v0], m_vertexb[v1], m_vertexb[v2]); + render_triangle<10>(cliprect, has_texture ? rd_scan_vertex_color_tex : rd_scan_vertex_color, m_vertexb[v2], m_vertexb[v3], m_vertexb[v0]); + } + else if (has_texture) { - int r = (color >> 16) & 0xff; - int g = (color >> 8) & 0xff; - int b = color & 0xff; - - r = ((((r * poly_light_r * ibri) >> 16) * ifog) + (poly_fog_r * (65536 - ifog))) >> 16; - g = ((((g * poly_light_g * ibri) >> 16) * ifog) + (poly_fog_g * (65536 - ifog))) >> 16; - b = ((((b * poly_light_b * ibri) >> 16) * ifog) + (poly_fog_b * (65536 - ifog))) >> 16; - - if (r < 0) r = 0; - if (r > 255) r = 255; - if (g < 0) g = 0; - if (g > 255) g = 255; - if (b < 0) b = 0; - if (b > 255) b = 255; - - fb[x] = (color & 0xff000000) | (r << 16) | (g << 8) | b; - zb[x] = z; + render_triangle<6>(cliprect, rd_scan_tex, m_vertexb[v0], m_vertexb[v1], m_vertexb[v2]); + render_triangle<6>(cliprect, rd_scan_tex, m_vertexb[v2], m_vertexb[v3], m_vertexb[v0]); } - } - - z += dz; - bri += dbri; - fog += dfog; - } -} - -void k001005_renderer::draw_scanline_tex(int32_t scanline, const extent_t &extent, const k001005_polydata &extradata, int threadid) -{ -// int pal_chip = (extradata.texture_palette & 0x8) ? 1 : 0; - k001006_device *k001006 = downcast<k001006_device*>(m_k001006); - - int tex_page = extradata.texture_page * 0x40000; - int palette_index = (extradata.texture_palette & 0x7) * 256; - float z = extent.param[POLY_Z].start; - float u = extent.param[POLY_U].start; - float v = extent.param[POLY_V].start; - float w = extent.param[POLY_W].start; - float dz = extent.param[POLY_Z].dpdx; - float du = extent.param[POLY_U].dpdx; - float dv = extent.param[POLY_V].dpdx; - float dw = extent.param[POLY_W].dpdx; - float bri = extent.param[POLY_BRI].start; - float dbri = extent.param[POLY_BRI].dpdx; - float fog = extent.param[POLY_FOG].start; - float dfog = extent.param[POLY_FOG].dpdx; - int texture_mirror_x = extradata.texture_mirror_x; - int texture_mirror_y = extradata.texture_mirror_y; - int texture_x = extradata.texture_x; - int texture_y = extradata.texture_y; - int texture_width = extradata.texture_width; - int texture_height = extradata.texture_height; - - int poly_light_r = extradata.light_r + extradata.ambient_r; - int poly_light_g = extradata.light_g + extradata.ambient_g; - int poly_light_b = extradata.light_b + extradata.ambient_b; - if (poly_light_r > 255) poly_light_r = 255; - if (poly_light_g > 255) poly_light_g = 255; - if (poly_light_b > 255) poly_light_b = 255; - int poly_fog_r = extradata.fog_r; - int poly_fog_g = extradata.fog_g; - int poly_fog_b = extradata.fog_b; - - uint32_t *const fb = &m_fb[m_fb_page]->pix(scanline); - float *const zb = (float*)&m_zb->pix(scanline); - - int *x_mirror_table = m_tex_mirror_table[texture_mirror_x][texture_width].get(); - int *y_mirror_table = m_tex_mirror_table[texture_mirror_y][texture_height].get(); - - for (int x = extent.startx; x < extent.stopx; x++) - { - int ibri = (int)(bri); - int ifog = (int)(fog); - - if (ibri < 0) ibri = 0; - if (ibri > 255) ibri = 255; - if (ifog < 0) ifog = 0; - if (ifog > 65536) ifog = 65536; - - if (z <= zb[x]) - { - float oow = 1.0f / w; - uint32_t color; - int iu, iv; - int iiv, iiu; - - iu = u * oow * 0.0625f; - iv = v * oow * 0.0625f; - - iiu = texture_x + x_mirror_table[iu & 0x7f]; - iiv = texture_y + y_mirror_table[iv & 0x7f]; - - color = k001006->fetch_texel(tex_page, palette_index, iiu, iiv); - - if (color & 0xff000000) + else { - int r = (color >> 16) & 0xff; - int g = (color >> 8) & 0xff; - int b = color & 0xff; - - r = ((((r * poly_light_r * ibri) >> 16) * ifog) + (poly_fog_r * (65536 - ifog))) >> 16; - g = ((((g * poly_light_g * ibri) >> 16) * ifog) + (poly_fog_g * (65536 - ifog))) >> 16; - b = ((((b * poly_light_b * ibri) >> 16) * ifog) + (poly_fog_b * (65536 - ifog))) >> 16; - - if (r < 0) r = 0; - if (r > 255) r = 255; - if (g < 0) g = 0; - if (g > 255) g = 255; - if (b < 0) b = 0; - if (b > 255) b = 255; - - fb[x] = 0xff000000 | (r << 16) | (g << 8) | b; - zb[x] = z; + render_triangle<3>(cliprect, rd_scan_color, m_vertexb[v0], m_vertexb[v1], m_vertexb[v2]); + render_triangle<3>(cliprect, rd_scan_color, m_vertexb[v2], m_vertexb[v3], m_vertexb[v0]); } } - - u += du; - v += dv; - z += dz; - w += dw; - bri += dbri; - fog += dfog; - } -} - -void k001005_renderer::draw_scanline_gouraud_blend(int32_t scanline, const extent_t &extent, const k001005_polydata &extradata, int threadid) -{ - float z = extent.param[POLY_Z].start; - float dz = extent.param[POLY_Z].dpdx; - float r = extent.param[POLY_R].start; - float dr = extent.param[POLY_R].dpdx; - float g = extent.param[POLY_G].start; - float dg = extent.param[POLY_G].dpdx; - float b = extent.param[POLY_B].start; - float db = extent.param[POLY_B].dpdx; - float a = extent.param[POLY_A].start; - float da = extent.param[POLY_A].dpdx; - uint32_t *const fb = &m_fb[m_fb_page]->pix(scanline); - float *const zb = (float*)&m_zb->pix(scanline); - - for (int x = extent.startx; x < extent.stopx; x++) - { - if (z <= zb[x]) - { - int ir = (int)(r); - int ig = (int)(g); - int ib = (int)(b); - int ia = (int)(a); - - if (ia > 0) + else + { + if (has_vertex_color) { - if (ia != 0xff) - { - int sr = (fb[x] >> 16) & 0xff; - int sg = (fb[x] >> 8) & 0xff; - int sb = fb[x] & 0xff; - - ir = ((ir * ia) >> 8) + ((sr * (0xff-ia)) >> 8); - ig = ((ig * ia) >> 8) + ((sg * (0xff-ia)) >> 8); - ib = ((ib * ia) >> 8) + ((sb * (0xff-ia)) >> 8); - } - - if (ir < 0) ir = 0; - if (ir > 255) ir = 255; - if (ig < 0) ig = 0; - if (ig > 255) ig = 255; - if (ib < 0) ib = 0; - if (ib > 255) ib = 255; - - fb[x] = 0xff000000 | (ir << 16) | (ig << 8) | ib; - zb[x] = z; + render_triangle<10>(cliprect, has_texture ? rd_scan_vertex_color_tex : rd_scan_vertex_color, m_vertexb[v1], m_vertexb[v2], m_vertexb[v3]); + } + else if (has_texture) + { + render_triangle<6>(cliprect, rd_scan_tex, m_vertexb[v1], m_vertexb[v2], m_vertexb[v3]); + } + else + { + render_triangle<3>(cliprect, rd_scan_color, m_vertexb[v1], m_vertexb[v2], m_vertexb[v3]); } } - - z += dz; - r += dr; - g += dg; - b += db; - a += da; } + return index - start_index; } -void k001005_renderer::draw_scanline_tex_gouraud(int32_t scanline, const extent_t& extent, const k001005_polydata& extradata, int threadid) +void k001005_renderer::render_polygons() { - k001006_device* k001006 = downcast<k001006_device*>(m_k001006); - - int tex_page = extradata.texture_page * 0x40000; - int palette_index = (extradata.texture_palette & 0x7) * 256; - float z = extent.param[POLY_Z].start; - float u = extent.param[POLY_U].start; - float v = extent.param[POLY_V].start; - float w = extent.param[POLY_W].start; - float dz = extent.param[POLY_Z].dpdx; - float du = extent.param[POLY_U].dpdx; - float dv = extent.param[POLY_V].dpdx; - float dw = extent.param[POLY_W].dpdx; - float bri = extent.param[POLY_BRI].start; - float dbri = extent.param[POLY_BRI].dpdx; - float fog = extent.param[POLY_FOG].start; - float dfog = extent.param[POLY_FOG].dpdx; - float r = extent.param[POLY_ALTR].start; - float dr = extent.param[POLY_ALTR].dpdx; - float g = extent.param[POLY_ALTG].start; - float dg = extent.param[POLY_ALTG].dpdx; - float b = extent.param[POLY_ALTB].start; - float db = extent.param[POLY_ALTB].dpdx; - float a = extent.param[POLY_ALTA].start; - float da = extent.param[POLY_ALTA].dpdx; - int texture_mirror_x = extradata.texture_mirror_x; - int texture_mirror_y = extradata.texture_mirror_y; - int texture_x = extradata.texture_x; - int texture_y = extradata.texture_y; - int texture_width = extradata.texture_width; - int texture_height = extradata.texture_height; - - int poly_light_r = extradata.light_r + extradata.ambient_r; - int poly_light_g = extradata.light_g + extradata.ambient_g; - int poly_light_b = extradata.light_b + extradata.ambient_b; - if (poly_light_r > 255) poly_light_r = 255; - if (poly_light_g > 255) poly_light_g = 255; - if (poly_light_b > 255) poly_light_b = 255; - int poly_fog_r = extradata.fog_r; - int poly_fog_g = extradata.fog_g; - int poly_fog_b = extradata.fog_b; - - uint32_t* const fb = &m_fb[m_fb_page]->pix(scanline); - float* const zb = (float*)&m_zb->pix(scanline); - - int* x_mirror_table = m_tex_mirror_table[texture_mirror_x][texture_width].get(); - int* y_mirror_table = m_tex_mirror_table[texture_mirror_y][texture_height].get(); + uint32_t* fifo = m_3dfifo.get(); + int index = 0; - for (int x = extent.startx; x < extent.stopx; x++) + do { - int ibri = (int)(bri); - int ifog = (int)(fog); - - if (ibri < 0) ibri = 0; - if (ibri > 255) ibri = 255; - if (ifog < 0) ifog = 0; - if (ifog > 65536) ifog = 65536; - - int ir = (int)(r); - int ig = (int)(g); - int ib = (int)(b); - int ia = (int)(a); + uint32_t cmd = fifo[index++]; - if (z <= zb[x]) + if (cmd == 0x80000000 || cmd == 0x80000018) { - float oow = 1.0f / w; - uint32_t color; - int iu, iv; - int iiv, iiu; - - iu = u * oow * 0.0625f; - iv = v * oow * 0.0625f; - - iiu = texture_x + x_mirror_table[iu & 0x7f]; - iiv = texture_y + y_mirror_table[iv & 0x7f]; - - color = k001006->fetch_texel(tex_page, palette_index, iiu, iiv); - - if (color & 0xff000000) - { - // texture - int r = (color >> 16) & 0xff; - int g = (color >> 8) & 0xff; - int b = color & 0xff; - - r = ((((r * poly_light_r * ibri) >> 16) * ifog) + (poly_fog_r * (65536 - ifog))) >> 16; - g = ((((g * poly_light_g * ibri) >> 16) * ifog) + (poly_fog_g * (65536 - ifog))) >> 16; - b = ((((b * poly_light_b * ibri) >> 16) * ifog) + (poly_fog_b * (65536 - ifog))) >> 16; - - if (r < 0) r = 0; - if (r > 255) r = 255; - if (g < 0) g = 0; - if (g > 255) g = 255; - if (b < 0) b = 0; - if (b > 255) b = 255; - - fb[x] = 0xff000000 | (r << 16) | (g << 8) | b; - zb[x] = z; - } - else - { - // gouraud color - if (ia != 0xff) - { - int sr = (fb[x] >> 16) & 0xff; - int sg = (fb[x] >> 8) & 0xff; - int sb = fb[x] & 0xff; - - ir = ((ir * ia) >> 8) + ((sr * (0xff - ia)) >> 8); - ig = ((ig * ia) >> 8) + ((sg * (0xff - ia)) >> 8); - ib = ((ib * ia) >> 8) + ((sb * (0xff - ia)) >> 8); - } - - ir = ((((ir * poly_light_r * ibri) >> 16) * ifog) + (poly_fog_r * (65536 - ifog))) >> 16; - ig = ((((ig * poly_light_g * ibri) >> 16) * ifog) + (poly_fog_g * (65536 - ifog))) >> 16; - ib = ((((ib * poly_light_b * ibri) >> 16) * ifog) + (poly_fog_b * (65536 - ifog))) >> 16; - - if (ir < 0) ir = 0; - if (ir > 255) ir = 255; - if (ig < 0) ig = 0; - if (ig > 255) ig = 255; - if (ib < 0) ib = 0; - if (ib > 255) ib = 255; - - fb[x] = 0xff000000 | (ir << 16) | (ig << 8) | ib; - zb[x] = z; - } } - - u += du; - v += dv; - z += dz; - w += dw; - bri += dbri; - fog += dfog; - r += dr; - g += dg; - b += db; - a += da; + else if ((cmd & 0xffff0000) == 0x80000000) + { + index += parse_polygon(index, cmd); + } } + while (index < m_3dfifo_ptr); + + m_3dfifo_ptr = 0; + wait(); } @@ -1472,6 +687,7 @@ void k001005_renderer::draw(bitmap_rgb32 &bitmap, const rectangle &cliprect) } } } + } @@ -1487,7 +703,6 @@ k001005_device::k001005_device(const machine_config &mconfig, const char *tag, d , m_ram_ptr(0) , m_fifo_read_ptr(0) , m_fifo_write_ptr(0) - , m_reg_far_z(0) { m_ram[0] = nullptr; m_ram[1] = nullptr; @@ -1513,7 +728,6 @@ void k001005_device::device_start() save_item(NAME(m_ram_ptr)); save_item(NAME(m_fifo_read_ptr)); save_item(NAME(m_fifo_write_ptr)); - save_item(NAME(m_reg_far_z)); } //------------------------------------------------- @@ -1603,7 +817,7 @@ uint32_t k001005_device::read(address_space &space, offs_t offset, uint32_t mem_ return m_ram[0][(m_ram_ptr++) & 0x3fffff]; } - default: + default: //osd_printf_debug("%s m_r: %08X, %08X\n", machine().describe_context(), offset, mem_mask); break; } @@ -1642,16 +856,6 @@ void k001005_device::write(address_space &space, offs_t offset, uint32_t data, u m_renderer->push_data(data); -#if LOG_POLY_FIFO - printf("0x%08X, ", data); - count++; - if (count >= 8) - { - count = 0; - printf("\n"); - } -#endif - // !!! HACK to get past the FIFO B test (GTI Club & Thunder Hurricane) !!! if (dsp->pc() == 0x201ee) { @@ -1670,39 +874,59 @@ void k001005_device::write(address_space &space, offs_t offset, uint32_t data, u case 0x100: break; - case 0x101: break; // viewport x and width? - case 0x102: break; // viewport y and height? + case 0x101: break; // framebuffer width? + case 0x102: break; // framebuffer height? - case 0x104: break; // viewport center x? (usually 0xff) - case 0x105: break; // viewport center y? (usually 0xbf) + case 0x103: m_renderer->m_viewport_min_x = data & 0xffff; break; + case 0x104: m_renderer->m_viewport_max_x = data & 0xffff; break; + case 0x105: m_renderer->m_viewport_max_y = data & 0xffff; break; + case 0x106: m_renderer->m_viewport_min_y = data & 0xffff; break; - case 0x108: // far Z value, 4 exponent bits? - { - // this register seems to hold the 4 missing exponent bits... - m_reg_far_z = (m_reg_far_z & 0x0000ffff) | ((data & 0xf) << 16); - m_renderer->set_param(K001005_FAR_Z, m_reg_far_z); - break; - } + case 0x107: m_renderer->m_viewport_center_x = data & 0xffff; break; + case 0x108: m_renderer->m_viewport_center_y = data & 0xffff; break; case 0x109: // far Z value { - // the SHARC code throws away the bottom 11 bits of mantissa and the top 5 bits (to fit in a 16-bit register?) - m_reg_far_z = (m_reg_far_z & 0xffff0000) | (data & 0xffff); - m_renderer->set_param(K001005_FAR_Z, m_reg_far_z); + // the SHARC code throws away the bottom 11 bits of mantissa and the top 5 bits (to fit in a 16-bit register?) + m_renderer->m_far_z = u2f((data & 0xffff) << 11); break; } - case 0x10a: m_renderer->set_param(K001005_LIGHT_R, data & 0xff); break; - case 0x10b: m_renderer->set_param(K001005_LIGHT_G, data & 0xff); break; - case 0x10c: m_renderer->set_param(K001005_LIGHT_B, data & 0xff); break; + case 0x10a: m_renderer->m_light_r = data & 0xff; break; + case 0x10b: m_renderer->m_light_g = data & 0xff; break; + case 0x10c: m_renderer->m_light_b = data & 0xff; break; - case 0x10d: m_renderer->set_param(K001005_AMBIENT_R, data & 0xff); break; - case 0x10e: m_renderer->set_param(K001005_AMBIENT_G, data & 0xff); break; - case 0x10f: m_renderer->set_param(K001005_AMBIENT_B, data & 0xff); break; + case 0x10d: m_renderer->m_ambient_r = data & 0xff; break; + case 0x10e: m_renderer->m_ambient_g = data & 0xff; break; + case 0x10f: m_renderer->m_ambient_b = data & 0xff; break; - case 0x110: m_renderer->set_param(K001005_FOG_R, data & 0xff); break; - case 0x111: m_renderer->set_param(K001005_FOG_G, data & 0xff); break; - case 0x112: m_renderer->set_param(K001005_FOG_B, data & 0xff); break; + case 0x110: m_renderer->m_fog_r = data & 0xff; break; + case 0x111: m_renderer->m_fog_g = data & 0xff; break; + case 0x112: m_renderer->m_fog_b = data & 0xff; break; + + case 0x117: // linear fog start Z + { + // 4 bits exponent + 12 bits mantissa, similar to far Z value + // value of 0xffff is used to effectively turn off fog + + // reconstruct float from 16-bit data + // assuming implicit exponent 1001xxxx, sign bit 0 (z-values are all positive) + m_renderer->m_reg_fog_start = data & 0xffff; + m_renderer->m_fog_start_z = u2f((0x90000 | (data & 0xffff)) << 11); + break; + } + case 0x118: // linear fog end Z + { + // 4 bits exponent + 12 bits mantissa, similar to far Z value + m_renderer->m_fog_end_z = u2f((0x90000 | (data & 0xffff)) << 11); + break; + } + + case 0x119: // 1 / (end_fog - start_fog) ? + { + // 5 bits exponent + 11 bits mantissa + break; + } case 0x11a: |