rasterize: add fog emulation

This commit is contained in:
zeromus 2009-07-26 21:13:38 +00:00
parent 9828895c53
commit db610129bb
4 changed files with 93 additions and 14 deletions

View File

@ -24,6 +24,7 @@ Graphics:
bug: fix disp fifo capture
bug: fix simultaneous vram display and capture via same bank
bug: swrast: add clear image and scroll emulation
bug: swrast: add fog emulation
bug: swrast: fixes to shadow rendering
Windows:

View File

@ -1973,20 +1973,16 @@ void VIEWPORT::decode(u32 v)
void gfx3d_glClearColor(u32 v)
{
gfx3d.clearColor = v;
}
void gfx3d_glFogColor(u32 v)
{
gfx3d.fogColor[0] = ((float)((v )&0x1F))/31.0f;
gfx3d.fogColor[1] = ((float)((v>> 5)&0x1F))/31.0f;
gfx3d.fogColor[2] = ((float)((v>>10)&0x1F))/31.0f;
gfx3d.fogColor[3] = ((float)((v>>16)&0x1F))/31.0f;
gfx3d.fogColor = v;
}
void gfx3d_glFogOffset (u32 v)
{
gfx3d.fogOffset = (float)(v&0xffff);
gfx3d.fogOffset = (v&0x7fff);
}
void gfx3d_glClearDepth(u32 v)
@ -2307,7 +2303,10 @@ static void gfx3d_doFlush()
gfx3d.enableAlphaBlending = BIT3(control);
gfx3d.enableAntialiasing = BIT4(control);
gfx3d.enableEdgeMarking = BIT5(control);
gfx3d.enableFogAlphaOnly = BIT6(control);
gfx3d.enableFog = BIT7(control);
gfx3d.enableClearImage = BIT14(control);
gfx3d.fogShift = (control>>8)&0xF;
int polycount = polylist->count;
@ -3123,6 +3122,10 @@ SFORMAT SF_GFX3D[]={
{ "GSEB", 4, 1, &gfx3d.enableAlphaBlending},
{ "GSEX", 4, 1, &gfx3d.enableAntialiasing},
{ "GSEE", 4, 1, &gfx3d.enableEdgeMarking},
{ "GSEC", 4, 1, &gfx3d.enableClearImage},
{ "GSEF", 4, 1, &gfx3d.enableFog},
{ "GSEO", 4, 1, &gfx3d.enableFogAlphaOnly},
{ "GFSH", 4, 1, &gfx3d.fogShift},
{ "GSSH", 4, 1, &gfx3d.shading},
{ "GSWB", 4, 1, &gfx3d.wbuffer},
{ "GSSM", 4, 1, &gfx3d.sortmode},
@ -3130,7 +3133,7 @@ SFORMAT SF_GFX3D[]={
{ "GSVP", 4, 1, &viewport},
{ "GSCC", 4, 1, &gfx3d.clearColor},
{ "GSCD", 4, 1, &gfx3d.clearDepth},
{ "GSFC", 4, 4, gfx3d.fogColor},
{ "GSFC", 4, 4, &gfx3d.fogColor},
{ "GSFO", 4, 1, &gfx3d.fogOffset},
{ "GST2", 2, 32, gfx3d.u16ToonTable},
{ "GSST", 4, 128, shininessTable},

View File

@ -185,6 +185,9 @@ struct GFX3D
, enableAntialiasing(false)
, enableEdgeMarking(false)
, enableClearImage(false)
, enableFog(false)
, enableFogAlphaOnly(false)
, fogShift(0)
, shading(TOON)
, polylist(0)
, vertlist(0)
@ -193,12 +196,14 @@ struct GFX3D
, clearColor(0)
, frameCtr(0)
, frameCtrRaw(0)
, fogOffset(0)
, fogColor(0)
{
fogColor[0] = fogColor[1] = fogColor[2] = fogColor[3] = 0;
fogOffset = 0;
}
BOOL enableTexturing, enableAlphaTest, enableAlphaBlending,
enableAntialiasing, enableEdgeMarking, enableClearImage;
enableAntialiasing, enableEdgeMarking, enableClearImage, enableFog, enableFogAlphaOnly;
u32 fogShift;
static const u32 TOON = 0;
static const u32 HIGHLIGHT = 1;
@ -214,8 +219,13 @@ struct GFX3D
u32 clearDepth;
u32 clearColor;
float fogColor[4];
float fogOffset;
#include "PACKED.h"
struct {
u32 fogColor;
u32 pad[3]; //for savestate compatibility as of 26-jul-09
};
#include "PACKED_END.h"
u32 fogOffset;
//ticks every time flush() is called
int frameCtr;

View File

@ -194,6 +194,7 @@ struct PolyAttr
u8 alpha;
bool backfacing;
bool translucent;
u8 fogged;
bool isVisible(bool backfacing)
{
@ -214,6 +215,7 @@ struct PolyAttr
polyid = (polyAttr>>24)&0x3F;
alpha = (polyAttr>>16)&0x1F;
drawBackPlaneIntersectingPolys = BIT12(val);
fogged = BIT15(val);
}
} polyAttr;
@ -239,7 +241,10 @@ struct Fragment
u8 stencil;
u8 isTranslucentPoly;
struct {
u8 isTranslucentPoly:1;
u8 fogged:1;
};
};
static VERT* verts[MAX_CLIPPED_VERTS];
@ -252,7 +257,7 @@ INLINE static void SubmitVertex(int vert_index, VERT& rawvert)
static Fragment screen[256*192];
static FragmentColor screenColor[256*192];
static FragmentColor toonTable[32];
static u8 fogTable[32768];
FORCEINLINE int iround(float f) {
return (int)f; //lol
@ -559,6 +564,7 @@ static FORCEINLINE void pixel(int adr,float r, float g, float b, float invu, flo
{
destFragment.polyid.opaque = polyAttr.polyid;
destFragment.isTranslucentPoly = polyAttr.translucent?1:0;
destFragment.fogged = polyAttr.fogged;
destFragmentColor = shaderOutput;
}
else
@ -584,6 +590,8 @@ static FORCEINLINE void pixel(int adr,float r, float g, float b, float invu, flo
//alpha blending and write color
alphaBlend(destFragmentColor, shaderOutput);
destFragment.fogged &= polyAttr.fogged;
}
//depth writing
@ -1010,6 +1018,30 @@ static void SoftRastFramebufferProcess()
//}
if(gfx3d.enableFog)
{
u32 r = gfx3d.fogColor&0x1F;
u32 g = (gfx3d.fogColor>>5)&0x1F;
u32 b = (gfx3d.fogColor>>10)&0x1F;
u32 a = (gfx3d.fogColor>>16)&0x1F;
for(int i=0;i<256*192;i++)
{
Fragment &destFragment = screen[i];
if(!destFragment.fogged) continue;
FragmentColor &destFragmentColor = screenColor[i];
u32 fogIndex = destFragment.depth>>9;
assert(fogIndex<32768);
u8 fog = fogTable[fogIndex];
if(fog==127) fog=128;
if(!gfx3d.enableFogAlphaOnly)
{
destFragmentColor.r = ((128-fog)*destFragmentColor.r + r*fog)>>7;
destFragmentColor.g = ((128-fog)*destFragmentColor.g + g*fog)>>7;
destFragmentColor.b = ((128-fog)*destFragmentColor.b + b*fog)>>7;
}
destFragmentColor.a = ((128-fog)*destFragmentColor.a + a*fog)>>7;
}
}
}
static void SoftRastConvertFramebuffer()
@ -1218,6 +1250,8 @@ static void SoftRastRender()
clearFragment.polyid.translucent = kUnsetTranslucentPolyID;
clearFragment.depth = gfx3d.clearDepth;
clearFragment.stencil = 0;
clearFragment.isTranslucentPoly = 0;
clearFragment.fogged = BIT15(gfx3d.clearColor);
for(int i=0;i<256*192;i++)
screen[i] = clearFragment;
@ -1254,6 +1288,7 @@ static void SoftRastRender()
depth &= 0x7FFF;
//TODO - might consider a lookup table for this
dst->depth = gfx3d_extendDepth_15_to_24(depth);
dst->fogged = BIT15(depth);
dstColor++;
dst++;
@ -1272,6 +1307,36 @@ static void SoftRastRender()
toonTable[i].b = (gfx3d.u16ToonTable[i]>>10)&0x1F;
}
//setup fog variables (but only if fog is enabled)
if(gfx3d.enableFog)
{
u8* fogDensity = MMU.MMU_MEM[ARMCPU_ARM9][0x40] + 0x360;
//TODO - this might be a little slow;
//we might need to hash all the variables and only recompute this when something changes
const int increment = (0x400 >> gfx3d.fogShift);
for(u32 i=0;i<32768;i++) {
if(i<gfx3d.fogOffset) {
fogTable[i] = fogDensity[0];
continue;
}
for(int j=0;j<31;j++) {
u32 value = gfx3d.fogOffset + increment*(j+1);
if(i<=value) {
if(j==0) {
fogTable[i] = fogDensity[0];
goto done;
} else {
int lastValue = value - increment;
fogTable[i] = ((value-i)*fogDensity[j-1] + (increment-(value-i))*fogDensity[j])/increment;
goto done;
}
}
}
fogTable[i] = fogDensity[31];
done: ;
}
}
//convert colors to float to get more precision in case we need it
for(int i=0;i<gfx3d.vertlist->count;i++)
gfx3d.vertlist->list[i].color_to_float();