// license:BSD-3-Clause // copyright-holders:R. Belmont, Olivier Galibert, ElSemi, Angelo Salese /******************************************************************** Sega Model 2 3D rasterization functions ********************************************************************/ #undef MODEL2_CHECKER #undef MODEL2_TEXTURED #undef MODEL2_TRANSLUCENT #ifndef MODEL2_FUNC #error "Model 2 renderer: No function defined!" #endif #ifndef MODEL2_FUNC_NAME #error "Model 2 renderer: No function name defined!" #endif #if MODEL2_FUNC == 0 #undef MODEL2_CHECKER #undef MODEL2_TEXTURED #undef MODEL2_TRANSLUCENT #elif MODEL2_FUNC == 1 #undef MODEL2_CHECKER #undef MODEL2_TEXTURED #define MODEL2_TRANSLUCENT #elif MODEL2_FUNC == 2 #undef MODEL2_CHECKER #define MODEL2_TEXTURED #undef MODEL2_TRANSLUCENT #elif MODEL2_FUNC == 3 #undef MODEL2_CHECKER #define MODEL2_TEXTURED #define MODEL2_TRANSLUCENT #elif MODEL2_FUNC == 4 #define MODEL2_CHECKER #undef MODEL2_TEXTURED #undef MODEL2_TRANSLUCENT #elif MODEL2_FUNC == 5 #define MODEL2_CHECKER #undef MODEL2_TEXTURED #define MODEL2_TRANSLUCENT #elif MODEL2_FUNC == 6 #define MODEL2_CHECKER #define MODEL2_TEXTURED #undef MODEL2_TRANSLUCENT #elif MODEL2_FUNC == 7 #define MODEL2_CHECKER #define MODEL2_TEXTURED #define MODEL2_TRANSLUCENT #else #error "Model 2 renderer: Invalid function selected!" #endif #ifndef MODEL2_TEXTURED /* non-textured render path */ void MODEL2_FUNC_NAME(int32_t scanline, const extent_t& extent, const m2_poly_extra_data& object, int threadid) { #if !defined( MODEL2_TRANSLUCENT) model2_state *state = object.state; bitmap_rgb32 *destmap = (bitmap_rgb32 *)&m_destmap; uint32_t *p = &destmap->pix32(scanline); // uint8_t *gamma_value = &state->m_gamma_table[0]; /* extract color information */ // const uint16_t *colortable_r = &state->m_colorxlat[0x0000/2]; // const uint16_t *colortable_g = &state->m_colorxlat[0x4000/2]; // const uint16_t *colortable_b = &state->m_colorxlat[0x8000/2]; // const uint16_t *lumaram = &state->m_lumaram[0]; // uint32_t lumabase = object.lumabase; uint32_t color = object.colorbase; // uint8_t luma; uint32_t tr, tg, tb; int x; #endif /* if it's translucent, there's nothing to render */ #if defined( MODEL2_TRANSLUCENT) return; #else // luma = lumaram[(lumabase + (0xf << 3))]; // fix luma overflow // luma = std::min((int)luma,0x3f); color = state->m_palram[(color + 0x1000)] & 0xffff; // colortable_r += ((color >> 0) & 0x1f) << 8; // colortable_g += ((color >> 5) & 0x1f) << 8; // colortable_b += ((color >> 10) & 0x1f) << 8; /* we have the 6 bits of luma information along with 5 bits per color component */ /* now build and index into the master color lookup table and extract the raw RGB values */ // untextured path doesn't use luma & color table, cfr. Daytona and Motor Raid tr = pal5bit((color >> 0) & 0x1f); //colortable_r[(luma)] & 0xff; tg = pal5bit((color >> 5) & 0x1f); //colortable_g[(luma)] & 0xff; tb = pal5bit((color >> 10) & 0x1f); //colortable_b[(luma)] & 0xff; // tr = gamma_value[tr]; // tg = gamma_value[tg]; // tb = gamma_value[tb]; /* build the final color */ color = rgb_t(tr, tg, tb); for(x = extent.startx; x < extent.stopx; x++) #if defined(MODEL2_CHECKER) if ((x^scanline) & 1) p[x] = color; #else p[x] = color; #endif #endif } #else /* textured render path */ void MODEL2_FUNC_NAME(int32_t scanline, const extent_t& extent, const m2_poly_extra_data& object, int threadid) { model2_state *state = object.state; bitmap_rgb32 *destmap = (bitmap_rgb32 *)&m_destmap; uint32_t *p = &destmap->pix32(scanline); uint32_t tex_width = object.texwidth; uint32_t tex_height = object.texheight; /* extract color information */ const uint16_t *colortable_r = &state->m_colorxlat[0x0000/2]; const uint16_t *colortable_g = &state->m_colorxlat[0x4000/2]; const uint16_t *colortable_b = &state->m_colorxlat[0x8000/2]; const uint16_t *lumaram = &state->m_lumaram[0]; uint32_t colorbase = object.colorbase; uint32_t lumabase = object.lumabase; uint32_t tex_x = object.texx; uint32_t tex_y = object.texy; uint32_t tex_x_mask, tex_y_mask; uint32_t tex_mirr_x = object.texmirrorx; uint32_t tex_mirr_y = object.texmirrory; uint32_t *sheet = object.texsheet; uint8_t *gamma_value = &state->m_gamma_table[0]; float ooz = extent.param[0].start; float uoz = extent.param[1].start; float voz = extent.param[2].start; float dooz = extent.param[0].dpdx; float duoz = extent.param[1].dpdx; float dvoz = extent.param[2].dpdx; int x; tex_x_mask = tex_width - 1; tex_y_mask = tex_height - 1; colorbase = state->m_palram[(colorbase + 0x1000)] & 0x7fff; colortable_r += ((colorbase >> 0) & 0x1f) << 8; colortable_g += ((colorbase >> 5) & 0x1f) << 8; colortable_b += ((colorbase >> 10) & 0x1f) << 8; for(x = extent.startx; x < extent.stopx; x++, uoz += duoz, voz += dvoz, ooz += dooz) { float z = recip_approx(ooz) * 256.0f; int32_t u = uoz * z; int32_t v = voz * z; int tr, tg, tb; uint16_t t; uint8_t luma; int u2; int v2; #if defined(MODEL2_CHECKER) if ( ((x^scanline) & 1) == 0 ) continue; #endif u2 = (u >> 8) & tex_x_mask; v2 = (v >> 8) & tex_y_mask; if ( tex_mirr_x ) u2 = ( tex_width - 1 ) - u2; if ( tex_mirr_y ) v2 = ( tex_height - 1 ) - v2; t = get_texel( tex_x, tex_y, u2, v2, sheet ); #if defined(MODEL2_TRANSLUCENT) if ( t == 0x0f ) continue; #endif luma = lumaram[(lumabase + (t << 3))]; // Virtua Striker sets up a luma of 0x40 for national flags on bleachers, fix here. luma = std::min((int)luma,0x3f); // (Again) Virtua Striker seem to lookup colortable with a reversed endianness (stadium ads) // TODO: it breaks Mexican flag colors tho ... // luma^= 1; /* we have the 6 bits of luma information along with 5 bits per color component */ /* now build and index into the master color lookup table and extract the raw RGB values */ tr = colortable_r[(luma)] & 0xff; tg = colortable_g[(luma)] & 0xff; tb = colortable_b[(luma)] & 0xff; tr = gamma_value[tr]; tg = gamma_value[tg]; tb = gamma_value[tb]; p[x] = rgb_t(tr, tg, tb); } } #endif