mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-11-15 02:29:51 +01:00
Add fog support to software rasterizer (as if it wasn't slow enough already)
This commit is contained in:
1 parent
7e2f37abc1
commit
842817c91d
5 files changed
+61
-30
No files matched your search
@@ -196,6 +196,7 @@ void ProcessRect(const VertexData& v0, const VertexData& v1)
|
||||
buf[0].color0 = buf[1].color0 = buf[2].color0 = buf[3].color0;
|
||||
buf[0].color1 = buf[1].color1 = buf[2].color1 = buf[3].color1;
|
||||
buf[0].clippos.w = buf[1].clippos.w = buf[2].clippos.w = buf[3].clippos.w = 1.0f;
|
||||
buf[0].fogdepth = buf[1].fogdepth = buf[2].fogdepth = buf[3].fogdepth = 1.0f;
|
||||
|
||||
VertexData* topleft = &buf[0];
|
||||
VertexData* topright = &buf[1];
|
||||
|
||||
+48
-27
@@ -103,6 +103,15 @@ static inline u32 LookupColor(unsigned int index, unsigned int level)
|
||||
}
|
||||
}
|
||||
|
||||
static inline u8 ClampFogDepth(float fogdepth) {
|
||||
if (fogdepth <= 0.0f)
|
||||
return 0;
|
||||
else if (fogdepth >= 1.0f)
|
||||
return 255;
|
||||
else
|
||||
return (u8)(u32)(fogdepth * 255.0f);
|
||||
}
|
||||
|
||||
static inline void GetTexelCoordinates(int level, float s, float t, int& out_u, int& out_v)
|
||||
{
|
||||
int width = 1 << (gstate.texsize[level] & 0xf);
|
||||
@@ -936,7 +945,7 @@ static inline Vec3<int> AlphaBlendingResult(const Vec4<int> &source, const Vec4<
|
||||
}
|
||||
|
||||
template <bool clearMode>
|
||||
inline void DrawSinglePixel(const DrawingCoords &p, u16 z, const Vec4<int> &color_in) {
|
||||
inline void DrawSinglePixel(const DrawingCoords &p, u16 z, u8 fog, const Vec4<int> &color_in) {
|
||||
Vec4<int> prim_color = color_in;
|
||||
// Depth range test
|
||||
// TODO: Clear mode?
|
||||
@@ -955,7 +964,7 @@ inline void DrawSinglePixel(const DrawingCoords &p, u16 z, const Vec4<int> &colo
|
||||
|
||||
// In clear mode, it uses the alpha color as stencil.
|
||||
u8 stencil = clearMode ? prim_color.a() : GetPixelStencil(p.x, p.y);
|
||||
// TODO: Is it safe to ignore gstate.isDepthTestEnabled() when clear mode is enabled?
|
||||
// TODO: Is it safe to ignore gstate.isDepthTestEnabled() when clear mode is enabled? Probably yes
|
||||
if (!clearMode && (gstate.isStencilTestEnabled() || gstate.isDepthTestEnabled())) {
|
||||
if (gstate.isStencilTestEnabled() && !StencilTestPassed(stencil)) {
|
||||
stencil = ApplyStencilOp(gstate.getStencilOpSFail(), p.x, p.y);
|
||||
@@ -989,6 +998,14 @@ inline void DrawSinglePixel(const DrawingCoords &p, u16 z, const Vec4<int> &colo
|
||||
prim_color.b() <<= 1;
|
||||
}
|
||||
|
||||
if (gstate.isFogEnabled() && !gstate.isModeThrough() && !clearMode) {
|
||||
Vec3<int> fogColor = Vec3<int>::FromRGB(gstate.fogcolor);
|
||||
fogColor = (prim_color.rgb() * (int)fog + fogColor * (255 - (int)fog)) / 255;
|
||||
prim_color.r() = fogColor.r();
|
||||
prim_color.g() = fogColor.g();
|
||||
prim_color.b() = fogColor.b();
|
||||
}
|
||||
|
||||
const u32 old_color = GetPixelColor(p.x, p.y);
|
||||
u32 new_color;
|
||||
|
||||
@@ -1200,6 +1217,7 @@ void DrawTriangleSlice(
|
||||
int w1_base = orient2d(v2.screenpos, v0.screenpos, pprime);
|
||||
int w2_base = orient2d(v0.screenpos, v1.screenpos, pprime);
|
||||
|
||||
// Step forward to y1 (slice..)
|
||||
w0_base += orient2dIncY(d12.x) * 16 * y1;
|
||||
w1_base += orient2dIncY(-d02.x) * 16 * y1;
|
||||
w2_base += orient2dIncY(d01.x) * 16 * y1;
|
||||
@@ -1226,20 +1244,18 @@ void DrawTriangleSlice(
|
||||
p.x = (p.x + 1) & 0x3FF) {
|
||||
|
||||
// If p is on or inside all edges, render pixel
|
||||
// TODO: Should we render if the pixel is both on the left and the right side? (i.e. degenerated triangle)
|
||||
if (w0 + bias0 >= 0 && w1 + bias1 >= 0 && w2 + bias2 >= 0) {
|
||||
// TODO: Check if this check is still necessary
|
||||
if (w0 == 0 && w1 == 0 && w2 == 0)
|
||||
int wsum = w0 + w1 + w2;
|
||||
if (wsum == 0.0f)
|
||||
continue;
|
||||
|
||||
float wsum = 1.0f / (w0 + w1 + w2);
|
||||
float wsum_recip = 1.0f / (float)wsum;
|
||||
|
||||
Vec4<int> prim_color;
|
||||
Vec3<int> sec_color;
|
||||
if (gstate.getShadeMode() == GE_SHADE_GOURAUD && !clearMode) {
|
||||
// TODO: Is that the correct way to interpolate?
|
||||
prim_color = Interpolate(v0.color0, v1.color0, v2.color0, w0, w1, w2, wsum);
|
||||
sec_color = Interpolate(v0.color1, v1.color1, v2.color1, w0, w1, w2, wsum);
|
||||
// Does the PSP do perspective-correct color interpolation? The GC doesn't.
|
||||
prim_color = Interpolate(v0.color0, v1.color0, v2.color0, w0, w1, w2, wsum_recip);
|
||||
sec_color = Interpolate(v0.color1, v1.color1, v2.color1, w0, w1, w2, wsum_recip);
|
||||
} else {
|
||||
prim_color = v2.color0;
|
||||
sec_color = v2.color1;
|
||||
@@ -1247,8 +1263,8 @@ void DrawTriangleSlice(
|
||||
|
||||
if (gstate.isTextureMapEnabled() && !clearMode) {
|
||||
if (gstate.isModeThrough()) {
|
||||
// TODO: Is it really this simple?
|
||||
Vec2<float> texcoords = Interpolate(v0.texturecoords, v1.texturecoords, v2.texturecoords, w0, w1, w2, wsum);
|
||||
// Texture coordinate interpolation must definitely be perspective-correct.
|
||||
Vec2<float> texcoords = Interpolate(v0.texturecoords, v1.texturecoords, v2.texturecoords, w0, w1, w2, wsum_recip);
|
||||
ApplyTexturing(prim_color, texcoords.s(), texcoords.t(), maxTexLevel, magFilt, texptr, texbufwidthbits);
|
||||
} else {
|
||||
float s = 0, t = 0;
|
||||
@@ -1269,15 +1285,18 @@ void DrawTriangleSlice(
|
||||
#endif
|
||||
}
|
||||
|
||||
// TODO: Fogging
|
||||
int fog = 255;
|
||||
if (gstate.isFogEnabled() && !clearMode) {
|
||||
fog = ClampFogDepth(((float)v0.fogdepth * w0 + (float)v1.fogdepth * w1 + (float)v2.fogdepth * w2) * wsum_recip);
|
||||
}
|
||||
|
||||
u16 z = v2.screenpos.z;
|
||||
// TODO: Is that the correct way to interpolate?
|
||||
// Without the (u32), this causes an ICE in some versions of gcc.
|
||||
if (!flatZ)
|
||||
z = (u16)(u32)(((float)v0.screenpos.z * w0 + (float)v1.screenpos.z * w1 + (float)v2.screenpos.z * w2) * wsum);
|
||||
z = (u16)(u32)(((float)v0.screenpos.z * w0 + (float)v1.screenpos.z * w1 + (float)v2.screenpos.z * w2) * wsum_recip);
|
||||
|
||||
DrawSinglePixel<clearMode>(p, z, prim_color);
|
||||
DrawSinglePixel<clearMode>(p, z, fog, prim_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1296,11 +1315,10 @@ void DrawTriangle(const VertexData& v0, const VertexData& v1, const VertexData&
|
||||
if (d01.x * d02.y - d01.y * d02.x < 0)
|
||||
return;
|
||||
|
||||
// Is the division and multiplication just &= ~0xF ?
|
||||
int minX = std::min(std::min(v0.screenpos.x, v1.screenpos.x), v2.screenpos.x) / 16 * 16;
|
||||
int minY = std::min(std::min(v0.screenpos.y, v1.screenpos.y), v2.screenpos.y) / 16 * 16;
|
||||
int maxX = std::max(std::max(v0.screenpos.x, v1.screenpos.x), v2.screenpos.x) / 16 * 16;
|
||||
int maxY = std::max(std::max(v0.screenpos.y, v1.screenpos.y), v2.screenpos.y) / 16 * 16;
|
||||
int minX = std::min(std::min(v0.screenpos.x, v1.screenpos.x), v2.screenpos.x) & ~0xF;
|
||||
int minY = std::min(std::min(v0.screenpos.y, v1.screenpos.y), v2.screenpos.y) & ~0xF;
|
||||
int maxX = std::max(std::max(v0.screenpos.x, v1.screenpos.x), v2.screenpos.x) & ~0xF;
|
||||
int maxY = std::max(std::max(v0.screenpos.y, v1.screenpos.y), v2.screenpos.y) & ~0xF;
|
||||
|
||||
DrawingCoords scissorTL(gstate.getScissorX1(), gstate.getScissorY1(), 0);
|
||||
DrawingCoords scissorBR(gstate.getScissorX2(), gstate.getScissorY2(), 0);
|
||||
@@ -1400,14 +1418,15 @@ void DrawPoint(const VertexData &v0)
|
||||
|
||||
ScreenCoords pprime = pos;
|
||||
|
||||
// TODO: Fogging
|
||||
DrawingCoords p = TransformUnit::ScreenToDrawing(pprime);
|
||||
u16 z = pos.z;
|
||||
|
||||
u8 fog = ClampFogDepth(v0.fogdepth);
|
||||
|
||||
if (clearMode) {
|
||||
DrawSinglePixel<true>(p, z, prim_color);
|
||||
DrawSinglePixel<true>(p, z, v0.fogdepth, prim_color);
|
||||
} else {
|
||||
DrawSinglePixel<false>(p, z, prim_color);
|
||||
DrawSinglePixel<false>(p, z, v0.fogdepth, prim_color);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1476,11 +1495,15 @@ void DrawLine(const VertexData &v0, const VertexData &v1)
|
||||
if (x < scissorTL.x || y < scissorTL.y || x >= scissorBR.x || y >= scissorBR.y)
|
||||
continue;
|
||||
|
||||
// Interpolate between the two points.
|
||||
Vec4<int> c0 = (v0.color0 * (steps - i) + v1.color0 * i) / steps1;
|
||||
Vec3<int> sec_color = (v0.color1 * (steps - i) + v1.color1 * i) / steps1;
|
||||
// TODO: UVGenMode?
|
||||
Vec2<float> tc = (v0.texturecoords * (float)(steps - i) + v1.texturecoords * (float)i) / steps1;
|
||||
Vec4<int> prim_color = c0;
|
||||
|
||||
// TODO: Interpolate fog as well
|
||||
|
||||
float s = tc.s();
|
||||
float t = tc.t();
|
||||
|
||||
@@ -1500,13 +1523,11 @@ void DrawLine(const VertexData &v0, const VertexData &v1)
|
||||
|
||||
ScreenCoords pprime = ScreenCoords(x, y, z);
|
||||
|
||||
// TODO: Fogging
|
||||
DrawingCoords p = TransformUnit::ScreenToDrawing(pprime);
|
||||
|
||||
if (clearMode) {
|
||||
DrawSinglePixel<true>(p, z, prim_color);
|
||||
DrawSinglePixel<true>(p, z, v0.fogdepth, prim_color);
|
||||
} else {
|
||||
DrawSinglePixel<false>(p, z, prim_color);
|
||||
DrawSinglePixel<false>(p, z, v0.fogdepth, prim_color);
|
||||
}
|
||||
|
||||
x = x + xinc;
|
||||
|
||||
@@ -172,7 +172,13 @@ VertexData TransformUnit::ReadVertex(VertexReader& vreader)
|
||||
if (!gstate.isModeThrough()) {
|
||||
vertex.modelpos = ModelCoords(pos[0], pos[1], pos[2]);
|
||||
vertex.worldpos = WorldCoords(TransformUnit::ModelToWorld(vertex.modelpos));
|
||||
vertex.clippos = ClipCoords(TransformUnit::ViewToClip(TransformUnit::WorldToView(vertex.worldpos)));
|
||||
ModelCoords viewpos = TransformUnit::WorldToView(vertex.worldpos);
|
||||
vertex.clippos = ClipCoords(TransformUnit::ViewToClip(viewpos));
|
||||
if (gstate.isFogEnabled()) {
|
||||
vertex.fogdepth = (viewpos.z + getFloat24(gstate.fog1)) * getFloat24(gstate.fog2);
|
||||
} else {
|
||||
vertex.fogdepth = 1.0f;
|
||||
}
|
||||
vertex.screenpos = ClipToScreenInternal(vertex.clippos, &outside_range_flag);
|
||||
|
||||
if (vreader.hasNormal()) {
|
||||
@@ -187,6 +193,7 @@ VertexData TransformUnit::ReadVertex(VertexReader& vreader)
|
||||
vertex.screenpos.y = (u32)pos[1] * 16 + gstate.getOffsetY16();
|
||||
vertex.screenpos.z = pos[2];
|
||||
vertex.clippos.w = 1.f;
|
||||
vertex.fogdepth = 1.f;
|
||||
}
|
||||
|
||||
return vertex;
|
||||
|
||||
@@ -93,8 +93,9 @@ struct VertexData
|
||||
screenpos = ::Lerp(a.screenpos, b.screenpos, t); // TODO: Should use a LerpInt (?)
|
||||
texturecoords = ::Lerp(a.texturecoords, b.texturecoords, t);
|
||||
normal = ::Lerp(a.normal, b.normal, t);
|
||||
fogdepth = ::Lerp(a.fogdepth, b.fogdepth, t);
|
||||
|
||||
u16 t_int =(u16)(t*256);
|
||||
u16 t_int = (u16)(t*256);
|
||||
color0 = LerpInt<Vec4<int>,256>(a.color0, b.color0, t_int);
|
||||
color1 = LerpInt<Vec3<int>,256>(a.color1, b.color1, t_int);
|
||||
}
|
||||
@@ -108,6 +109,7 @@ struct VertexData
|
||||
WorldCoords worldnormal;
|
||||
Vec4<int> color0;
|
||||
Vec3<int> color1;
|
||||
float fogdepth;
|
||||
};
|
||||
|
||||
class VertexReader;
|
||||
|
||||
+1
-1
Submodule native updated: 93a7d0c67e...316d6ab84d.
Reference in new issue
Block a user