mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-04-02 11:01:50 -04:00
Merge pull request #9682 from unknownbrackets/softgpu-light
SoftGPU: Match GLES lighting better, use floats
This commit is contained in:
commit
1f1ed5bb4d
6 changed files with 64 additions and 70 deletions
|
@ -316,7 +316,7 @@ struct GPUgstate {
|
|||
GELightType getLightType(int chan) const { return static_cast<GELightType>((ltype[chan] >> 8) & 3); }
|
||||
bool isDirectionalLight(int chan) const { return getLightType(chan) == GE_LIGHTTYPE_DIRECTIONAL; }
|
||||
bool isPointLight(int chan) const { return getLightType(chan) == GE_LIGHTTYPE_POINT; }
|
||||
bool isSpotLight(int chan) const { return getLightType(chan) == GE_LIGHTTYPE_SPOT; }
|
||||
bool isSpotLight(int chan) const { return getLightType(chan) >= GE_LIGHTTYPE_SPOT; }
|
||||
GEShadeMode getShadeMode() const { return static_cast<GEShadeMode>(shademodel & 1); }
|
||||
unsigned int getAmbientR() const { return ambientcolor&0xFF; }
|
||||
unsigned int getAmbientG() const { return (ambientcolor>>8)&0xFF; }
|
||||
|
|
|
@ -156,6 +156,7 @@ void ProcessRect(const VertexData& v0, const VertexData& v1)
|
|||
// Color and depth values of second vertex are used for the whole rectangle
|
||||
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].fogdepth = buf[1].fogdepth = buf[2].fogdepth = buf[3].fogdepth = 1.0f;
|
||||
|
||||
VertexData* topleft = &buf[0];
|
||||
VertexData* topright = &buf[1];
|
||||
|
|
|
@ -23,21 +23,22 @@ namespace Lighting {
|
|||
|
||||
void Process(VertexData& vertex, bool hasColor)
|
||||
{
|
||||
Vec3<int> mec = Vec3<int>(gstate.getMaterialEmissiveR(), gstate.getMaterialEmissiveG(), gstate.getMaterialEmissiveB());
|
||||
const int materialupdate = gstate.materialupdate & (hasColor ? 7 : 0);
|
||||
|
||||
Vec3<int> mac = hasColor && (gstate.materialupdate&1)
|
||||
? vertex.color0.rgb()
|
||||
: Vec3<int>(gstate.getMaterialAmbientR(), gstate.getMaterialAmbientG(), gstate.getMaterialAmbientB());
|
||||
Vec3<int> final_color = mec + mac * Vec3<int>(gstate.getAmbientR(), gstate.getAmbientG(), gstate.getAmbientB()) / 255;
|
||||
Vec3<int> specular_color(0, 0, 0);
|
||||
Vec3<float> vcol0 = vertex.color0.rgb().Cast<float>() * Vec3<float>::AssignToAll(1.0f / 255.0f);
|
||||
Vec3<float> mec = Vec3<float>::FromRGB(gstate.getMaterialEmissive());
|
||||
|
||||
Vec3<float> mac = (materialupdate & 1) ? vcol0 : Vec3<float>::FromRGB(gstate.getMaterialAmbientRGBA());
|
||||
Vec3<float> final_color = mec + mac * Vec3<float>::FromRGB(gstate.getAmbientRGBA());
|
||||
Vec3<float> specular_color(0.0f, 0.0f, 0.0f);
|
||||
|
||||
for (unsigned int light = 0; light < 4; ++light) {
|
||||
// Always calculate texture coords from lighting results if environment mapping is active
|
||||
// TODO: specular lighting should affect this, too!
|
||||
// TODO: Should specular lighting should affect this, too? Doesn't in GLES.
|
||||
// TODO: Not sure if this really should be done even if lighting is disabled altogether
|
||||
if (gstate.getUVGenMode() == GE_TEXMAP_ENVIRONMENT_MAP) {
|
||||
Vec3<float> L = Vec3<float>(getFloat24(gstate.lpos[3*light]&0xFFFFFF), getFloat24(gstate.lpos[3*light+1]&0xFFFFFF),getFloat24(gstate.lpos[3*light+2]&0xFFFFFF));
|
||||
float diffuse_factor = Dot(L,vertex.worldnormal) / L.Length() / vertex.worldnormal.Length();
|
||||
Vec3<float> L = Vec3<float>(getFloat24(gstate.lpos[3 * light]), getFloat24(gstate.lpos[3 * light + 1]),getFloat24(gstate.lpos[3 * light + 2]));
|
||||
float diffuse_factor = Dot(L.Normalized(), vertex.worldnormal);
|
||||
|
||||
if (gstate.getUVLS0() == (int)light)
|
||||
vertex.texturecoords.s() = (diffuse_factor + 1.f) / 2.f;
|
||||
|
@ -55,14 +56,16 @@ void Process(VertexData& vertex, bool hasColor)
|
|||
continue;
|
||||
|
||||
// L = vector from vertex to light source
|
||||
// TODO: Should transfer the light positions to world/view space for these calculations
|
||||
Vec3<float> L = Vec3<float>(getFloat24(gstate.lpos[3*light]&0xFFFFFF), getFloat24(gstate.lpos[3*light+1]&0xFFFFFF),getFloat24(gstate.lpos[3*light+2]&0xFFFFFF));
|
||||
L -= vertex.worldpos;
|
||||
float d = L.Length();
|
||||
// TODO: Should transfer the light positions to world/view space for these calculations?
|
||||
Vec3<float> L = Vec3<float>(getFloat24(gstate.lpos[3 * light]), getFloat24(gstate.lpos[3 * light + 1]),getFloat24(gstate.lpos[3 * light + 2]));
|
||||
if (!gstate.isDirectionalLight(light)) {
|
||||
L -= vertex.worldpos;
|
||||
}
|
||||
float d = L.Normalize();
|
||||
|
||||
float lka = getFloat24(gstate.latt[3*light]&0xFFFFFF);
|
||||
float lkb = getFloat24(gstate.latt[3*light+1]&0xFFFFFF);
|
||||
float lkc = getFloat24(gstate.latt[3*light+2]&0xFFFFFF);
|
||||
float lka = getFloat24(gstate.latt[3 * light]);
|
||||
float lkb = getFloat24(gstate.latt[3 * light + 1]);
|
||||
float lkc = getFloat24(gstate.latt[3 * light + 2]);
|
||||
float att = 1.f;
|
||||
if (!gstate.isDirectionalLight(light)) {
|
||||
att = 1.f / (lka + lkb * d + lkc * d * d);
|
||||
|
@ -72,11 +75,11 @@ void Process(VertexData& vertex, bool hasColor)
|
|||
|
||||
float spot = 1.f;
|
||||
if (gstate.isSpotLight(light)) {
|
||||
Vec3<float> dir = Vec3<float>(getFloat24(gstate.ldir[3*light]&0xFFFFFF), getFloat24(gstate.ldir[3*light+1]&0xFFFFFF),getFloat24(gstate.ldir[3*light+2]&0xFFFFFF));
|
||||
float _spot = Dot(-L,dir) / d / dir.Length();
|
||||
float cutoff = getFloat24(gstate.lcutoff[light]&0xFFFFFF);
|
||||
if (_spot > cutoff) {
|
||||
float conv = getFloat24(gstate.lconv[light]&0xFFFFFF);
|
||||
Vec3<float> dir = Vec3<float>(getFloat24(gstate.ldir[3 * light]), getFloat24(gstate.ldir[3 * light + 1]),getFloat24(gstate.ldir[3 * light + 2]));
|
||||
float _spot = Dot(dir.Normalized(), L);
|
||||
float cutoff = getFloat24(gstate.lcutoff[light]);
|
||||
if (_spot >= cutoff) {
|
||||
float conv = getFloat24(gstate.lconv[light]);
|
||||
spot = pow(_spot, conv);
|
||||
} else {
|
||||
spot = 0.f;
|
||||
|
@ -84,69 +87,56 @@ void Process(VertexData& vertex, bool hasColor)
|
|||
}
|
||||
|
||||
// ambient lighting
|
||||
Vec3<int> lac = Vec3<int>(gstate.getLightAmbientColorR(light), gstate.getLightAmbientColorG(light), gstate.getLightAmbientColorB(light));
|
||||
final_color.r() += (int)(att * spot * lac.r() * mac.r() / 255);
|
||||
final_color.g() += (int)(att * spot * lac.g() * mac.g() / 255);
|
||||
final_color.b() += (int)(att * spot * lac.b() * mac.b() / 255);
|
||||
Vec3<float> lac = Vec3<float>::FromRGB(gstate.getLightAmbientColor(light));
|
||||
final_color += lac * mac * att * spot;
|
||||
|
||||
// diffuse lighting
|
||||
Vec3<int> ldc = Vec3<int>(gstate.getDiffuseColorR(light), gstate.getDiffuseColorG(light), gstate.getDiffuseColorB(light));
|
||||
Vec3<int> mdc = hasColor && (gstate.materialupdate&2)
|
||||
? vertex.color0.rgb()
|
||||
: Vec3<int>(gstate.getMaterialDiffuseR(), gstate.getMaterialDiffuseG(), gstate.getMaterialDiffuseB());
|
||||
Vec3<float> ldc = Vec3<float>::FromRGB(gstate.getDiffuseColor(light));
|
||||
Vec3<float> mdc = (materialupdate & 2) ? vcol0 : Vec3<float>::FromRGB(gstate.getMaterialDiffuse());
|
||||
|
||||
float diffuse_factor = Dot(L,vertex.worldnormal) / d / vertex.worldnormal.Length();
|
||||
float diffuse_factor = Dot(L, vertex.worldnormal);
|
||||
if (gstate.isUsingPoweredDiffuseLight(light)) {
|
||||
float k = getFloat24(gstate.materialspecularcoef&0xFFFFFF);
|
||||
diffuse_factor = pow(diffuse_factor, k);
|
||||
float k = gstate.getMaterialSpecularCoef();
|
||||
// TODO: Validate Tales of the World: Radiant Mythology (#2424.)
|
||||
// pow(0.0, 0.0) may be undefined, but the PSP seems to treat it as 1.0.
|
||||
if (diffuse_factor <= 0.0f && k == 0.0f) {
|
||||
diffuse_factor = 1.0f;
|
||||
} else {
|
||||
diffuse_factor = pow(diffuse_factor, k);
|
||||
}
|
||||
}
|
||||
|
||||
if (diffuse_factor > 0.f) {
|
||||
final_color.r() += (int)(att * spot * ldc.r() * mdc.r() * diffuse_factor / 255);
|
||||
final_color.g() += (int)(att * spot * ldc.g() * mdc.g() * diffuse_factor / 255);
|
||||
final_color.b() += (int)(att * spot * ldc.b() * mdc.b() * diffuse_factor / 255);
|
||||
final_color += ldc * mdc * diffuse_factor * att * spot;
|
||||
}
|
||||
|
||||
if (gstate.isUsingSpecularLight(light)) {
|
||||
Vec3<float> E(0.f, 0.f, 1.f);
|
||||
Mat3x3<float> view_matrix(gstate.viewMatrix);
|
||||
Vec3<float> worldE = view_matrix.Inverse() * (E - Vec3<float>(gstate.viewMatrix[9], gstate.viewMatrix[10], gstate.viewMatrix[11]));
|
||||
Vec3<float> H = worldE / worldE.Length() + L / L.Length();
|
||||
Vec3<float> H = L + Vec3<float>(0.f, 0.f, 1.f);
|
||||
|
||||
Vec3<int> lsc = Vec3<int>(gstate.getSpecularColorR(light), gstate.getSpecularColorG(light), gstate.getSpecularColorB(light));
|
||||
Vec3<int> msc = hasColor && (gstate.materialupdate&4)
|
||||
? vertex.color0.rgb()
|
||||
: Vec3<int>(gstate.getMaterialSpecularR(), gstate.getMaterialSpecularG(), gstate.getMaterialSpecularB());
|
||||
Vec3<float> lsc = Vec3<float>::FromRGB(gstate.getSpecularColor(light));
|
||||
Vec3<float> msc = (materialupdate & 4) ? vcol0 : Vec3<float>::FromRGB(gstate.getMaterialSpecular());
|
||||
|
||||
float specular_factor = Dot(H,vertex.worldnormal) / H.Length() / vertex.worldnormal.Length();
|
||||
float k = getFloat24(gstate.materialspecularcoef&0xFFFFFF);
|
||||
float specular_factor = Dot(H.Normalized(), vertex.worldnormal);
|
||||
float k = gstate.getMaterialSpecularCoef();
|
||||
specular_factor = pow(specular_factor, k);
|
||||
|
||||
if (specular_factor > 0.f) {
|
||||
specular_color.r() += (int)(att * spot * lsc.r() * msc.r() * specular_factor / 255);
|
||||
specular_color.g() += (int)(att * spot * lsc.g() * msc.g() * specular_factor / 255);
|
||||
specular_color.b() += (int)(att * spot * lsc.b() * msc.b() * specular_factor / 255);
|
||||
specular_color += lsc * msc * specular_factor * att * spot;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vertex.color0.r() = final_color.r();
|
||||
vertex.color0.g() = final_color.g();
|
||||
vertex.color0.b() = final_color.b();
|
||||
int maa = (materialupdate & 1) ? vertex.color0.a() : gstate.getMaterialAmbientA();
|
||||
int final_alpha = (gstate.getAmbientA() * maa) / 255;
|
||||
|
||||
if (gstate.isUsingSecondaryColor()) {
|
||||
vertex.color1 = specular_color.Clamp(0, 255);
|
||||
Vec3<int> final_color_int = (final_color.Clamp(0.0f, 1.0f) * 255.0f).Cast<int>();
|
||||
vertex.color0 = Vec4<int>(final_color_int, final_alpha);
|
||||
vertex.color1 = (specular_color.Clamp(0.0f, 1.0f) * 255.0f).Cast<int>();
|
||||
} else {
|
||||
vertex.color0.r() += specular_color.r();
|
||||
vertex.color0.g() += specular_color.g();
|
||||
vertex.color0.b() += specular_color.b();
|
||||
vertex.color1 = Vec3<int>(0, 0, 0);
|
||||
Vec3<int> final_color_int = ((final_color + specular_color).Clamp(0.0f, 1.0f) * 255.0f).Cast<int>();
|
||||
vertex.color0 = Vec4<int>(final_color_int, final_alpha);
|
||||
}
|
||||
|
||||
int maa = hasColor && (gstate.materialupdate&1) ? vertex.color0.a() : gstate.getMaterialAmbientA();
|
||||
vertex.color0.a() = gstate.getAmbientA() * maa / 255;
|
||||
|
||||
vertex.color0 = vertex.color0.Clamp(0, 255);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
|
|
@ -97,8 +97,8 @@ DrawingCoords TransformUnit::ScreenToDrawing(const ScreenCoords& coords)
|
|||
{
|
||||
DrawingCoords ret;
|
||||
// TODO: What to do when offset > coord?
|
||||
ret.x = (((u32)coords.x - gstate.getOffsetX16()) / 16) & 0x3ff;
|
||||
ret.y = (((u32)coords.y - gstate.getOffsetY16()) / 16) & 0x3ff;
|
||||
ret.x = ((s32)coords.x - gstate.getOffsetX16()) / 16;
|
||||
ret.y = ((s32)coords.y - gstate.getOffsetY16()) / 16;
|
||||
ret.z = coords.z;
|
||||
return ret;
|
||||
}
|
||||
|
@ -178,6 +178,7 @@ VertexData TransformUnit::ReadVertex(VertexReader& vreader)
|
|||
ModelCoords viewpos = TransformUnit::WorldToView(vertex.worldpos);
|
||||
vertex.clippos = ClipCoords(TransformUnit::ViewToClip(viewpos));
|
||||
if (gstate.isFogEnabled()) {
|
||||
// TODO: Validate inf/nan.
|
||||
vertex.fogdepth = (viewpos.z + getFloat24(gstate.fog1)) * getFloat24(gstate.fog2);
|
||||
} else {
|
||||
vertex.fogdepth = 1.0f;
|
||||
|
@ -188,6 +189,8 @@ VertexData TransformUnit::ReadVertex(VertexReader& vreader)
|
|||
vertex.worldnormal = TransformUnit::ModelToWorldNormal(vertex.normal);
|
||||
// TODO: Isn't there a flag that controls whether to normalize the normal?
|
||||
vertex.worldnormal /= vertex.worldnormal.Length();
|
||||
} else {
|
||||
vertex.worldnormal = Vec3<float>(0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
Lighting::Process(vertex, vreader.hasColor0());
|
||||
|
|
|
@ -62,17 +62,17 @@ struct ScreenCoords
|
|||
struct DrawingCoords
|
||||
{
|
||||
DrawingCoords() {}
|
||||
DrawingCoords(u10 x, u10 y, u16 z) : x(x), y(y), z(z) {}
|
||||
DrawingCoords(s16 x, s16 y, u16 z) : x(x), y(y), z(z) {}
|
||||
|
||||
u10 x;
|
||||
u10 y;
|
||||
s16 x;
|
||||
s16 y;
|
||||
u16 z;
|
||||
|
||||
Vec2<u10> xy() const { return Vec2<u10>(x, y); }
|
||||
Vec2<s16> xy() const { return Vec2<s16>(x, y); }
|
||||
|
||||
DrawingCoords operator * (const float t) const
|
||||
{
|
||||
return DrawingCoords((u10)(x * t), (u10)(y * t), (u16)(z * t));
|
||||
return DrawingCoords((s16)(x * t), (s16)(y * t), (u16)(z * t));
|
||||
}
|
||||
|
||||
DrawingCoords operator + (const DrawingCoords& oth) const
|
||||
|
|
|
@ -714,7 +714,7 @@ Texture *D3D11DrawContext::CreateTexture(const TextureDesc &desc) {
|
|||
int w = desc.width;
|
||||
int h = desc.height;
|
||||
for (int i = 0; i < (int)desc.initData.size(); i++) {
|
||||
initData[i].pSysMem = desc.initData[0];
|
||||
initData[i].pSysMem = desc.initData[i];
|
||||
initData[i].SysMemPitch = (UINT)(w * DataFormatSizeInBytes(desc.format));
|
||||
initData[i].SysMemSlicePitch = (UINT)(w * h * DataFormatSizeInBytes(desc.format));
|
||||
w /= 2;
|
||||
|
|
Loading…
Add table
Reference in a new issue