diff --git a/GPU/Software/Rasterizer.cpp b/GPU/Software/Rasterizer.cpp index baaa46775e..f27eff03ee 100644 --- a/GPU/Software/Rasterizer.cpp +++ b/GPU/Software/Rasterizer.cpp @@ -133,6 +133,26 @@ u32 SampleNearest(int level, float s, float t) } else if (texfmt == GE_TFMT_8888) { srcptr += GetPixelDataOffset(32, texbufwidth*8, u, v); return DecodeRGBA8888(*(u32*)srcptr); + } else if (texfmt == GE_TFMT_CLUT32) { + srcptr += GetPixelDataOffset(32, texbufwidth*8, u, v); + + u32 val = *(u32*)srcptr; // TODO: Is this endian correct? + u16 index = (val >> gstate.getClutIndexShift()) & 0xFF; + index &= gstate.getClutIndexMask(); + index = (index & 0xFF) | gstate.getClutIndexStartPos(); // Topmost bit is copied from start pos + + // TODO: Assert that we're using GE_CMODE_32BIT_ABGR8888; + return DecodeRGBA8888(bswap32(*(u32*)&clut[index])); // TODO: No idea if that bswap is correct + } else if (texfmt == GE_TFMT_CLUT16) { + srcptr += GetPixelDataOffset(16, texbufwidth*8, u, v); + + u16 val = *(u16*)srcptr; // TODO: Is this endian correct? + u16 index = (((u32)val) >> gstate.getClutIndexShift()) & 0xFF; + index &= gstate.getClutIndexMask(); + index = (index & 0xFF) | gstate.getClutIndexStartPos(); // Topmost bit is copied from start pos + + // TODO: Assert that we're using GE_CMODE_32BIT_ABGR8888; + return DecodeRGBA8888(bswap32(*(u32*)&clut[index])); // TODO: No idea if that bswap is correct } else if (texfmt == GE_TFMT_CLUT8) { srcptr += GetPixelDataOffset(8, texbufwidth*8, u, v); @@ -227,7 +247,7 @@ static inline bool DepthTestPassed(int x, int y, u16 z) } } -bool IsRightSideOrFlatBottomLine(const Vec2& vertex, const Vec2& line1, const Vec2& line2) +static inline bool IsRightSideOrFlatBottomLine(const Vec2& vertex, const Vec2& line1, const Vec2& line2) { if (line1.y == line2.y) { // just check if vertex is above us => bottom line parallel to x-axis @@ -238,7 +258,7 @@ bool IsRightSideOrFlatBottomLine(const Vec2& vertex, const Vec2& line1 } } -void ApplyStencilOp(int op, int x, int y) +static inline void ApplyStencilOp(int op, int x, int y) { u8 old_stencil = GetPixelStencil(x, y); // TODO: Apply mask? u8 reference_stencil = gstate.getStencilTestRef(); // TODO: Apply mask? @@ -271,6 +291,57 @@ void ApplyStencilOp(int op, int x, int y) } } +static inline Vec4 GetTextureFunctionOutput(const Vec3& prim_color_rgb, int prim_color_a, float s, float t) +{ + Vec4 texcolor = Vec4::FromRGBA(/*TextureDecoder::*/SampleNearest(0, s, t)); + Vec3 out_rgb; + int out_a; + + bool rgba = (gstate.texfunc & 0x100) != 0; + + switch (gstate.getTextureFunction()) { + case GE_TEXFUNC_MODULATE: + out_rgb = prim_color_rgb * texcolor.rgb() / 255; + out_a = (rgba) ? (prim_color_a * texcolor.a() / 255) : prim_color_a; + break; + + case GE_TEXFUNC_DECAL: + { + int t = (rgba) ? texcolor.a() : 255; + int invt = (rgba) ? 255 - t : 0; + out_rgb = (invt * prim_color_rgb + t * texcolor.rgb()) / 255; + out_a = prim_color_a; + break; + } + + case GE_TEXFUNC_BLEND: + { + const Vec3 const255(255, 255, 255); + const Vec3 texenv(gstate.getTextureEnvColR(), gstate.getTextureEnvColG(), gstate.getTextureEnvColB()); + out_rgb = ((const255 - texcolor.rgb()) * prim_color_rgb + texcolor.rgb() * texenv) / 255; + out_a = prim_color_a * ((rgba) ? texcolor.a() : 255) / 255; + break; + } + + case GE_TEXFUNC_REPLACE: + out_rgb = texcolor.rgb(); + out_a = (rgba) ? texcolor.a() : prim_color_a; + break; + + case GE_TEXFUNC_ADD: + out_rgb = prim_color_rgb + texcolor.rgb(); + if (out_rgb.r() > 255) out_rgb.r() = 255; + if (out_rgb.g() > 255) out_rgb.g() = 255; + if (out_rgb.b() > 255) out_rgb.b() = 255; + out_a = prim_color_a * ((rgba) ? texcolor.a() : 255) / 255; + break; + + default: + ERROR_LOG(G3D, "Unknown texture function %x", gstate.getTextureFunction()); + } + + return Vec4(out_rgb.r(), out_rgb.g(), out_rgb.b(), out_a); +} // Draws triangle, vertices specified in counter-clockwise direction (TODO: Make sure this is actually enforced) void DrawTriangle(const VertexData& v0, const VertexData& v1, const VertexData& v2) { @@ -330,51 +401,9 @@ void DrawTriangle(const VertexData& v0, const VertexData& v1, const VertexData& // TODO: Also disable if vertex has no texture coordinates? if (gstate.isTextureMapEnabled() && !gstate.isModeClear()) { - Vec4 texcolor = Vec4::FromRGBA(/*TextureDecoder::*/SampleNearest(0, s, t)); - - bool rgba = (gstate.texfunc & 0x100) != 0; - - // texture function - switch (gstate.getTextureFunction()) { - case GE_TEXFUNC_MODULATE: - prim_color_rgb = prim_color_rgb * texcolor.rgb() / 255; - prim_color_a = (rgba) ? (prim_color_a * texcolor.a() / 255) : prim_color_a; - break; - - case GE_TEXFUNC_DECAL: - { - int t = (rgba) ? texcolor.a() : 255; - int invt = (rgba) ? 255 - t : 0; - prim_color_rgb = (invt * prim_color_rgb + t * texcolor.rgb()) / 255; - // prim_color_a = prim_color_a; - break; - } - - case GE_TEXFUNC_BLEND: - { - const Vec3 const255(255, 255, 255); - const Vec3 texenv(gstate.getTextureEnvColR(), gstate.getTextureEnvColG(), gstate.getTextureEnvColB()); - prim_color_rgb = ((const255 - texcolor.rgb()) * prim_color_rgb + texcolor.rgb() * texenv) / 255; - prim_color_a = prim_color_a * ((rgba) ? texcolor.a() : 255) / 255; - break; - } - - case GE_TEXFUNC_REPLACE: - prim_color_rgb = texcolor.rgb(); - prim_color_a = (rgba) ? texcolor.a() : prim_color_a; - break; - - case GE_TEXFUNC_ADD: - prim_color_rgb += texcolor.rgb(); - if (prim_color_rgb.r() > 255) prim_color_rgb.r() = 255; - if (prim_color_rgb.g() > 255) prim_color_rgb.g() = 255; - if (prim_color_rgb.b() > 255) prim_color_rgb.b() = 255; - prim_color_a = prim_color_a * ((rgba) ? texcolor.a() : 255) / 255; - break; - - default: - ERROR_LOG(G3D, "Unknown texture function %x", gstate.getTextureFunction()); - } + Vec4 out = GetTextureFunctionOutput(prim_color_rgb, prim_color_a, s, t); + prim_color_rgb = out.rgb(); + prim_color_a = out.a(); } if (gstate.isColorDoublingEnabled()) {