void Lighter::Light(float colorOut0[4], float colorOut1[4], const float colorIn[4], Vec3f pos, Vec3f norm) { Color4 in(colorIn); const Color4 *ambient; if (materialUpdate_ & 1) ambient = ∈ else ambient = &materialAmbient; const Color4 *diffuse; if (materialUpdate_ & 2) diffuse = ∈ else diffuse = &materialDiffuse; const Color4 *specular; if (materialUpdate_ & 4) specular = ∈ else specular = &materialSpecular; Color4 lightSum0 = globalAmbient * *ambient + materialEmissive; Color4 lightSum1(0, 0, 0, 0); for (int l = 0; l < 4; l++) { // can we skip this light? if (!gstate.isLightChanEnabled(l)) continue; GELightType type = gstate.getLightType(l); Vec3f toLight(0,0,0); Vec3f lightDir(0,0,0); if (type == GE_LIGHTTYPE_DIRECTIONAL) toLight = Vec3f(gstate_c.lightpos[l]); // lightdir is for spotlights else toLight = Vec3f(gstate_c.lightpos[l]) - pos; bool doSpecular = gstate.isUsingSpecularLight(l); bool poweredDiffuse = gstate.isUsingPoweredDiffuseLight(l); float distanceToLight = toLight.Length(); float dot = 0.0f; float angle = 0.0f; float lightScale = 0.0f; if (distanceToLight > 0.0f) { toLight /= distanceToLight; dot = Dot(toLight, norm); } // Clamp dot to zero. if (dot < 0.0f) dot = 0.0f; if (poweredDiffuse) dot = powf(dot, specCoef_); // Attenuation switch (type) { case GE_LIGHTTYPE_DIRECTIONAL: lightScale = 1.0f; break; case GE_LIGHTTYPE_POINT: lightScale = clamp(1.0f / (gstate_c.lightatt[l][0] + gstate_c.lightatt[l][1]*distanceToLight + gstate_c.lightatt[l][2]*distanceToLight*distanceToLight), 0.0f, 1.0f); break; case GE_LIGHTTYPE_SPOT: case GE_LIGHTTYPE_UNKNOWN: lightDir = gstate_c.lightdir[l]; angle = Dot(toLight.Normalized(), lightDir.Normalized()); if (angle >= gstate_c.lightangle[l]) lightScale = clamp(1.0f / (gstate_c.lightatt[l][0] + gstate_c.lightatt[l][1]*distanceToLight + gstate_c.lightatt[l][2]*distanceToLight*distanceToLight), 0.0f, 1.0f) * powf(angle, gstate_c.lightspotCoef[l]); break; default: // ILLEGAL break; } Color4 lightDiff(gstate_c.lightColor[1][l], 0.0f); Color4 diff = (lightDiff * *diffuse) * dot; // Real PSP specular Vec3f toViewer(0,0,1); // Better specular // Vec3f toViewer = (viewer - pos).Normalized(); if (doSpecular) { Vec3f halfVec = (toLight + toViewer); halfVec.Normalize(); dot = Dot(halfVec, norm); if (dot > 0.0f) { Color4 lightSpec(gstate_c.lightColor[2][l], 0.0f); lightSum1 += (lightSpec * *specular * (powf(dot, specCoef_) * lightScale)); } } if (gstate.isLightChanEnabled(l)) { Color4 lightAmbient(gstate_c.lightColor[0][l], 0.0f); lightSum0 += (lightAmbient * *ambient + diff) * lightScale; } } // 4? for (int i = 0; i < 4; i++) { colorOut0[i] = lightSum0[i] > 1.0f ? 1.0f : lightSum0[i]; colorOut1[i] = lightSum1[i] > 1.0f ? 1.0f : lightSum1[i]; } }
void Light(float colorOut[4], const float colorIn[4], Vec3 pos, Vec3 normal, float dots[4]) { // could cache a lot of stuff, such as ambient, across vertices... bool doShadeMapping = (gstate.texmapmode & 0x3) == 2; if (!doShadeMapping && !(gstate.lightEnable[0]&1) && !(gstate.lightEnable[1]&1) && !(gstate.lightEnable[2]&1) && !(gstate.lightEnable[3]&1)) { memcpy(colorOut, colorIn, sizeof(float) * 4); return; } Color4 emissive; emissive.GetFromRGB(gstate.materialemissive); Color4 globalAmbient; globalAmbient.GetFromRGB(gstate.ambientcolor); globalAmbient.GetFromA(gstate.ambientalpha); Vec3 norm = normal.Normalized(); Color4 in(colorIn); Color4 ambient; if (gstate.materialupdate & 1) { ambient = in; } else { ambient.GetFromRGB(gstate.materialambient); ambient.a=1.0f; } Color4 diffuse; if (gstate.materialupdate & 2) { diffuse = in; } else { diffuse.GetFromRGB(gstate.materialdiffuse); diffuse.a=1.0f; } Color4 specular; if (gstate.materialupdate & 4) { specular = in; } else { specular.GetFromRGB(gstate.materialspecular); specular.a=1.0f; } float specCoef = getFloat24(gstate.materialspecularcoef); Vec3 viewer(-gstate.viewMatrix[9], -gstate.viewMatrix[10], -gstate.viewMatrix[11]); Color4 lightSum = globalAmbient * ambient + emissive; // Try lights.elf - there's something wrong with the lighting for (int l = 0; l < 4; l++) { // can we skip this light? //if ((gstate.lightEnable[l] & 1) == 0) // && !doShadeMapping) // continue; GELightComputation comp = (GELightComputation)(gstate.ltype[l]&3); GELightType type = (GELightType)((gstate.ltype[l]>>8)&3); Vec3 toLight; if (type == GE_LIGHTTYPE_DIRECTIONAL) toLight = Vec3(gstate.lightpos[l]); // lightdir is for spotlights else toLight = Vec3(gstate.lightpos[l]) - pos; bool doSpecular = (comp != GE_LIGHTCOMP_ONLYDIFFUSE); bool poweredDiffuse = comp == GE_LIGHTCOMP_BOTHWITHPOWDIFFUSE; float lightScale = 1.0f; if (type != GE_LIGHTTYPE_DIRECTIONAL) { float distance = toLight.Normalize(); lightScale = 1.0f / (gstate.lightatt[l][0] + gstate.lightatt[l][1]*distance + gstate.lightatt[l][2]*distance*distance); if (lightScale > 1.0f) lightScale = 1.0f; } float dot = toLight * norm; // Clamp dot to zero. if (dot < 0.0f) dot = 0.0f; if (poweredDiffuse) dot = powf(dot, specCoef); Color4 diff = (gstate.lightColor[1][l] * diffuse) * (dot * lightScale); Color4 spec(0,0,0,0); // Real PSP specular Vec3 toViewer(0,0,1); // Better specular //Vec3 toViewer = (viewer - pos).Normalized(); if (doSpecular) { Vec3 halfVec = toLight; halfVec += toViewer; halfVec.Normalize(); dot = halfVec * norm; if (dot >= 0) { spec += (gstate.lightColor[2][l] * specular * (powf(dot, specCoef)*lightScale)); } } dots[l] = dot; if (gstate.lightEnable[l] & 1) { lightSum += gstate.lightColor[0][l]*ambient + diff + spec; } } for (int i = 0; i < 3; i++) colorOut[i] = lightSum[i]; }