suicmez/game/inc/suic_lighting.c
2025-12-20 15:09:29 +05:30

153 lines
4.7 KiB
C

#include "suic_lighting.h"
#include "suic_terrain.h"
#include <math.h>
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};
}