Ejemplo n.º 1
0
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];
    }
}
Ejemplo n.º 2
0
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];
}