#include "suic_lighting.h" #include "suic_terrain.h" #include SuicDirectionalLight suic_light_create(float dir_x, float dir_y, float dir_z, float intensity, float ambient) { SuicDirectionalLight light = {0}; light.direction = suic_v3_norm(suic_v3(dir_x, dir_y, dir_z)); light.color = suic_v3(1.0f, 1.0f, 1.0f); light.intensity = intensity; light.ambientIntensity = ambient; light.shadowBias = 0.005f; light.shadowIntensity = 0.4f; return light; } SuicDirectionalLight suic_light_create_default(void) { return suic_light_create(-0.8f, -1.0f, -0.6f, 1.2f, 0.3f); } SuicColor suic_light_apply(SuicColor base, SuicVec3 normal, SuicDirectionalLight *light) { SuicVec3 lightDir = light->direction; /* Diffuse: Lambertian */ float diff = fmaxf(0.0f, -(lightDir.x * normal.x + lightDir.y * normal.y + lightDir.z * normal.z)); float brightness = light->ambientIntensity + (diff * light->intensity * (1.0f - light->ambientIntensity)); int r = (int)(base.r * brightness); int g = (int)(base.g * brightness); int b = (int)(base.b * brightness); if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255; return (SuicColor){r, g, b, base.a}; } float suic_shadow_factor(SuicVec3 worldPos, SuicVec3 lightDir, float maxDist) { float distFromLight = fmaxf(0.0f, worldPos.y - 2.0f); float shadowIntensity = fmaxf(0.0f, 1.0f - (distFromLight / maxDist)); return 1.0f - (shadowIntensity * 0.15f); } float suic_shadow_temporal(SuicVec3 worldPos, float timePhase) { float noiseVal = sinf(worldPos.x * 0.5f + timePhase) * cosf(worldPos.z * 0.5f + timePhase); return 1.0f + (noiseVal * 0.02f); } SuicColor suic_light_apply_shadows(SuicColor base, SuicVec3 normal, SuicVec3 worldPos, SuicDirectionalLight *light) { float shadowFactor = suic_shadow_factor(worldPos, light->direction, 10.0f); float adjustedIntensity = light->intensity * shadowFactor; SuicVec3 lightDir = light->direction; float diff = fmaxf(0.0f, -(lightDir.x * normal.x + lightDir.y * normal.y + lightDir.z * normal.z)); float brightness = light->ambientIntensity + (diff * adjustedIntensity * (1.0f - light->ambientIntensity)); int r = (int)(base.r * brightness); int g = (int)(base.g * brightness); int b = (int)(base.b * brightness); if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255; return (SuicColor){r, g, b, base.a}; } float suic_ao_calculate(SuicVec3 worldPos, SuicVec3 normal) { float sampleRadius = 3.0f; float aoAccum = 0.0f; int numSamples = 8; float centerHeight = worldPos.y; float pi = 3.14159265f; for (int i = 0; i < numSamples; i++) { float angle = (2.0f * pi * (float)i) / (float)numSamples; float sx = worldPos.x + cosf(angle) * sampleRadius; float sz = worldPos.z + sinf(angle) * sampleRadius; float sh = suic_terrain_height(sx, sz); float heightDiff = sh - centerHeight; if (heightDiff > 0.1f) { float aoAmount = fminf(1.0f, heightDiff / 2.0f); aoAccum += aoAmount; } } float aoFactor = 1.0f - (aoAccum / (float)numSamples) * 0.6f; return fmaxf(0.2f, aoFactor); } SuicColor suic_light_apply_phong(SuicColor base, SuicVec3 normal, SuicVec3 worldPos, SuicVec3 camPos, SuicDirectionalLight *light) { SuicVec3 lightDir = suic_v3_norm(light->direction); SuicVec3 normal_n = suic_v3_norm(normal); SuicVec3 viewDir = suic_v3_norm(suic_v3_sub(camPos, worldPos)); /* Diffuse */ float diffuse = fmaxf(0.0f, -suic_v3_dot(lightDir, normal_n)); /* Specular: Blinn-Phong */ SuicVec3 negLight = suic_v3(-lightDir.x, -lightDir.y, -lightDir.z); SuicVec3 halfVec = suic_v3_norm(suic_v3_add(suic_v3_norm(negLight), viewDir)); float specular = powf(fmaxf(0.0f, suic_v3_dot(halfVec, normal_n)), 32.0f) * 0.5f; /* Ambient occlusion */ float ao = suic_ao_calculate(worldPos, normal_n); /* Shadow */ float shadowFactor = suic_shadow_factor(worldPos, light->direction, 10.0f); /* Combine */ float brightness = light->ambientIntensity * ao; brightness += diffuse * light->intensity * shadowFactor * (1.0f - light->ambientIntensity) * ao; brightness += specular * light->intensity * shadowFactor * 0.6f; brightness = fminf(1.0f, brightness); int r = (int)(base.r * brightness); int g = (int)(base.g * brightness); int b = (int)(base.b * brightness); if (r > 255) r = 255; if (g > 255) g = 255; if (b > 255) b = 255; return (SuicColor){r, g, b, base.a}; }