2012-01-22 18:39:42 +00:00
|
|
|
#include "lighting.h"
|
|
|
|
|
2011-12-10 13:25:22 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <math.h>
|
2012-01-22 18:39:42 +00:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <string.h>
|
2011-12-10 13:25:22 +00:00
|
|
|
|
|
|
|
#include "shared/types.h"
|
2012-01-29 17:39:56 +00:00
|
|
|
#include "color.h"
|
|
|
|
#include "euclid.h"
|
2012-01-23 23:45:33 +00:00
|
|
|
#include "renderer.h"
|
|
|
|
#include "scenery.h"
|
2012-01-29 17:39:56 +00:00
|
|
|
#include "sky.h"
|
|
|
|
#include "terrain.h"
|
|
|
|
#include "tools.h"
|
|
|
|
#include "water.h"
|
2012-01-22 18:39:42 +00:00
|
|
|
|
|
|
|
static LightDefinition _LIGHT_NULL;
|
|
|
|
|
|
|
|
void lightingInit()
|
|
|
|
{
|
|
|
|
_LIGHT_NULL.direction.x = 0.0;
|
|
|
|
_LIGHT_NULL.direction.y = 1.0;
|
|
|
|
_LIGHT_NULL.direction.z = 0.0;
|
2012-01-25 17:31:36 +00:00
|
|
|
_LIGHT_NULL.color = COLOR_BLACK;
|
2012-01-26 18:20:19 +00:00
|
|
|
_LIGHT_NULL.reflection = 0.0;
|
2012-01-25 17:31:36 +00:00
|
|
|
_LIGHT_NULL.filtered = 0;
|
|
|
|
_LIGHT_NULL.masked = 0;
|
|
|
|
_LIGHT_NULL.amplitude = 0.0;
|
2012-01-22 18:39:42 +00:00
|
|
|
}
|
2011-12-10 13:25:22 +00:00
|
|
|
|
2012-02-12 16:57:29 +00:00
|
|
|
void lightingQuit()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2012-04-22 17:12:39 +00:00
|
|
|
void lightingSave(PackStream* stream, LightingDefinition* definition)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2012-01-24 13:16:20 +00:00
|
|
|
int i;
|
|
|
|
|
2012-04-22 17:12:39 +00:00
|
|
|
packWriteInt(stream, &definition->autosetfromsky);
|
|
|
|
packWriteInt(stream, &definition->nblights);
|
2012-01-24 13:16:20 +00:00
|
|
|
for (i = 0; i < definition->nblights; i++)
|
|
|
|
{
|
2012-04-22 17:12:39 +00:00
|
|
|
v3Save(stream, &definition->lights[i].direction);
|
|
|
|
colorSave(stream, &definition->lights[i].color);
|
2012-06-17 09:40:40 +00:00
|
|
|
packWriteDouble(stream, &definition->lights[i].reflection);
|
2012-04-22 17:12:39 +00:00
|
|
|
packWriteInt(stream, &definition->lights[i].filtered);
|
|
|
|
packWriteInt(stream, &definition->lights[i].masked);
|
2012-06-17 09:40:40 +00:00
|
|
|
packWriteDouble(stream, &definition->lights[i].amplitude);
|
2012-01-24 13:16:20 +00:00
|
|
|
}
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
|
|
|
|
2012-04-22 17:12:39 +00:00
|
|
|
void lightingLoad(PackStream* stream, LightingDefinition* definition)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2012-01-24 13:16:20 +00:00
|
|
|
int i;
|
|
|
|
|
2012-04-22 17:12:39 +00:00
|
|
|
packReadInt(stream, &definition->autosetfromsky);
|
|
|
|
packReadInt(stream, &definition->nblights);
|
2012-01-24 13:16:20 +00:00
|
|
|
for (i = 0; i < definition->nblights; i++)
|
|
|
|
{
|
2012-04-22 17:12:39 +00:00
|
|
|
v3Load(stream, &definition->lights[i].direction);
|
|
|
|
colorLoad(stream, &definition->lights[i].color);
|
2012-06-17 09:40:40 +00:00
|
|
|
packReadDouble(stream, &definition->lights[i].reflection);
|
2012-04-22 17:12:39 +00:00
|
|
|
packReadInt(stream, &definition->lights[i].filtered);
|
|
|
|
packReadInt(stream, &definition->lights[i].masked);
|
2012-06-17 09:40:40 +00:00
|
|
|
packReadDouble(stream, &definition->lights[i].amplitude);
|
2012-01-24 13:16:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
lightingValidateDefinition(definition);
|
2012-01-22 18:39:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
LightingDefinition lightingCreateDefinition()
|
|
|
|
{
|
|
|
|
LightingDefinition definition;
|
|
|
|
|
|
|
|
definition.autosetfromsky = 0;
|
|
|
|
definition.nblights = 0;
|
|
|
|
definition._nbautolights = 0;
|
|
|
|
|
|
|
|
return definition;
|
|
|
|
}
|
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
void lightingDeleteDefinition(LightingDefinition* definition)
|
2012-01-22 18:39:42 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2012-01-23 23:45:33 +00:00
|
|
|
void lightingCopyDefinition(LightingDefinition* source, LightingDefinition* destination)
|
2012-01-22 18:39:42 +00:00
|
|
|
{
|
2012-01-23 23:45:33 +00:00
|
|
|
*destination = *source;
|
2012-01-22 18:39:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void lightingValidateDefinition(LightingDefinition* definition)
|
|
|
|
{
|
|
|
|
if (definition->autosetfromsky)
|
|
|
|
{
|
2012-01-23 23:45:33 +00:00
|
|
|
SkyDefinition sky;
|
|
|
|
|
|
|
|
sky = skyCreateDefinition();
|
|
|
|
sceneryGetSky(&sky);
|
|
|
|
definition->_nbautolights = skyGetLights(&sky, definition->_autolights, LIGHTING_MAX_LIGHTS);
|
|
|
|
skyDeleteDefinition(&sky);
|
2012-01-22 18:39:42 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
definition->_nbautolights = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int lightingGetLightCount(LightingDefinition* definition)
|
|
|
|
{
|
|
|
|
return definition->nblights;
|
|
|
|
}
|
|
|
|
|
|
|
|
LightDefinition lightingGetLight(LightingDefinition* definition, int light)
|
|
|
|
{
|
|
|
|
if (light >= 0 && light < definition->nblights)
|
|
|
|
{
|
|
|
|
return definition->lights[light];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return _LIGHT_NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int lightingAddLight(LightingDefinition* definition, LightDefinition light)
|
|
|
|
{
|
2012-01-23 23:45:33 +00:00
|
|
|
if (definition->nblights < LIGHTING_MAX_LIGHTS)
|
2012-01-22 18:39:42 +00:00
|
|
|
{
|
|
|
|
definition->lights[definition->nblights] = light;
|
|
|
|
return definition->nblights++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void lightingDeleteLight(LightingDefinition* definition, int light)
|
|
|
|
{
|
|
|
|
if (light >= 0 && light < definition->nblights)
|
|
|
|
{
|
|
|
|
if (definition->nblights > 1 && light < definition->nblights - 1)
|
|
|
|
{
|
|
|
|
memmove(definition->lights + light, definition->lights + light + 1, sizeof(LightDefinition) * definition->nblights - light - 1);
|
|
|
|
}
|
|
|
|
definition->nblights--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-06 10:13:34 +00:00
|
|
|
static int _getLightStatus(LightDefinition* definition, Renderer* renderer, Vector3 location, LightDefinition* result)
|
|
|
|
{
|
2012-06-05 20:22:12 +00:00
|
|
|
*result = *definition;
|
2012-05-06 10:13:34 +00:00
|
|
|
|
2012-06-05 20:22:12 +00:00
|
|
|
if (definition->masked || definition->filtered)
|
2012-05-06 10:13:34 +00:00
|
|
|
{
|
2012-06-05 20:22:12 +00:00
|
|
|
renderer->alterLight(renderer, result, location);
|
2012-05-06 10:13:34 +00:00
|
|
|
}
|
|
|
|
|
2012-06-05 20:22:12 +00:00
|
|
|
if (result->color.r > 0.0 || result->color.g > 0.0 || result->color.b > 0.0)
|
2012-05-06 10:13:34 +00:00
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static Color _applyDirectLight(LightDefinition* definition, Renderer* renderer, Vector3 location, Vector3 normal, SurfaceMaterial material)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
|
|
|
Color result, light;
|
2012-06-17 09:40:40 +00:00
|
|
|
double diffuse, specular, normal_norm;
|
2012-01-22 22:06:11 +00:00
|
|
|
Vector3 view, reflect, direction_inv;
|
2012-01-22 18:39:42 +00:00
|
|
|
|
2012-01-22 22:06:11 +00:00
|
|
|
light = definition->color;
|
2012-05-06 10:13:34 +00:00
|
|
|
direction_inv = v3Scale(definition->direction, -1.0);
|
2012-01-22 22:06:11 +00:00
|
|
|
|
2012-02-15 16:39:57 +00:00
|
|
|
if (definition->amplitude > 0.0)
|
|
|
|
{
|
2012-05-06 10:13:34 +00:00
|
|
|
/* TODO Sampling around light direction */
|
2012-02-15 16:39:57 +00:00
|
|
|
int xsamples, ysamples, samples, x, y;
|
2012-06-17 09:40:40 +00:00
|
|
|
double xstep, ystep, factor;
|
2012-02-15 16:39:57 +00:00
|
|
|
LightDefinition sublight;
|
|
|
|
|
|
|
|
ysamples = renderer->render_quality / 4 + 1;
|
|
|
|
xsamples = renderer->render_quality / 2 + 1;
|
|
|
|
samples = xsamples * ysamples + 1;
|
2012-06-17 09:40:40 +00:00
|
|
|
factor = 1.0 / (double)samples;
|
2012-02-15 16:39:57 +00:00
|
|
|
|
2012-06-17 09:40:40 +00:00
|
|
|
xstep = M_PI * 2.0 / (double)xsamples;
|
|
|
|
ystep = M_PI * 0.5 / (double)(ysamples - 1);
|
2012-02-15 16:39:57 +00:00
|
|
|
|
|
|
|
sublight = *definition;
|
|
|
|
sublight.amplitude = 0.0;
|
|
|
|
sublight.color.r *= factor;
|
|
|
|
sublight.color.g *= factor;
|
|
|
|
sublight.color.b *= factor;
|
|
|
|
|
2012-05-06 10:13:34 +00:00
|
|
|
result = _applyDirectLight(&sublight, renderer, location, normal, material);
|
2012-02-15 16:39:57 +00:00
|
|
|
for (x = 0; x < xsamples; x++)
|
|
|
|
{
|
|
|
|
for (y = 0; y < ysamples; y++)
|
|
|
|
{
|
|
|
|
sublight.direction.x = cos(x * xstep) * cos(y * ystep);
|
|
|
|
sublight.direction.y = -sin(y * ystep);
|
|
|
|
sublight.direction.z = sin(x * xstep) * cos(y * ystep);
|
2012-05-06 10:13:34 +00:00
|
|
|
light = _applyDirectLight(&sublight, renderer, location, normal, material);
|
2012-02-15 16:39:57 +00:00
|
|
|
result.r += light.r;
|
|
|
|
result.g += light.g;
|
|
|
|
result.b += light.b;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2012-01-24 13:59:54 +00:00
|
|
|
normal_norm = v3Norm(normal);
|
|
|
|
if (normal_norm > 1.0)
|
|
|
|
{
|
|
|
|
normal_norm = 1.0;
|
|
|
|
}
|
2011-12-10 13:25:22 +00:00
|
|
|
normal = v3Normalize(normal);
|
2012-01-24 13:59:54 +00:00
|
|
|
|
2012-01-22 22:06:11 +00:00
|
|
|
diffuse = v3Dot(direction_inv, normal);
|
2012-05-06 10:13:34 +00:00
|
|
|
/*diffuse = pow(diffuse * 0.5 + 0.5, 2.0);*/
|
2012-01-26 18:20:19 +00:00
|
|
|
diffuse = diffuse * 0.5 + 0.5;
|
2011-12-10 13:25:22 +00:00
|
|
|
if (diffuse > 0.0)
|
|
|
|
{
|
2012-01-26 18:20:19 +00:00
|
|
|
if (material.shininess > 0.0 && definition->reflection > 0.0)
|
2011-12-10 13:25:22 +00:00
|
|
|
{
|
2012-01-26 18:20:19 +00:00
|
|
|
view = v3Normalize(v3Sub(location, renderer->camera_location));
|
|
|
|
reflect = v3Sub(direction_inv, v3Scale(normal, 2.0 * v3Dot(direction_inv, normal)));
|
|
|
|
|
2012-01-30 16:40:17 +00:00
|
|
|
specular = v3Dot(reflect, view);
|
2012-01-25 17:31:36 +00:00
|
|
|
if (specular > 0.0)
|
|
|
|
{
|
2012-01-26 18:20:19 +00:00
|
|
|
specular = pow(specular, material.shininess);
|
2012-01-25 17:31:36 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
specular = 0.0;
|
|
|
|
}
|
2012-01-30 16:40:17 +00:00
|
|
|
specular *= material.reflection;
|
2011-12-10 13:25:22 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
specular = 0.0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
diffuse = 0.0;
|
|
|
|
specular = 0.0;
|
|
|
|
}
|
|
|
|
|
2012-01-26 18:20:19 +00:00
|
|
|
specular *= normal_norm * definition->reflection;
|
2012-01-24 13:59:54 +00:00
|
|
|
diffuse = 1.0 - normal_norm + diffuse * normal_norm;
|
|
|
|
|
2012-01-26 18:20:19 +00:00
|
|
|
result.r = material.base.r * diffuse * light.r + specular * light.r;
|
|
|
|
result.g = material.base.g * diffuse * light.g + specular * light.g;
|
|
|
|
result.b = material.base.b * diffuse * light.b + specular * light.b;
|
2012-01-22 22:06:11 +00:00
|
|
|
result.a = material.base.a;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2012-05-06 10:13:34 +00:00
|
|
|
void lightingGetStatus(LightingDefinition* definition, Renderer* renderer, Vector3 location, LightStatus* result)
|
2012-01-22 22:06:11 +00:00
|
|
|
{
|
|
|
|
int i;
|
2012-05-06 10:13:34 +00:00
|
|
|
|
|
|
|
result->nblights = 0;
|
|
|
|
|
2012-01-22 22:06:11 +00:00
|
|
|
for (i = 0; i < definition->nblights; i++)
|
|
|
|
{
|
2012-05-06 10:13:34 +00:00
|
|
|
if (_getLightStatus(definition->lights + i, renderer, location, result->lights + result->nblights))
|
|
|
|
{
|
|
|
|
result->nblights++;
|
|
|
|
}
|
2012-01-22 22:06:11 +00:00
|
|
|
}
|
|
|
|
for (i = 0; i < definition->_nbautolights; i++)
|
|
|
|
{
|
2012-05-06 10:13:34 +00:00
|
|
|
if (_getLightStatus(definition->_autolights + i, renderer, location, result->lights + result->nblights))
|
|
|
|
{
|
|
|
|
result->nblights++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Color lightingApplyStatusToSurface(Renderer* renderer, LightStatus* status, Vector3 location, Vector3 normal, SurfaceMaterial material)
|
|
|
|
{
|
|
|
|
Color result, lighted;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
result = COLOR_BLACK;
|
|
|
|
result.a = material.base.a;
|
|
|
|
|
|
|
|
for (i = 0; i < status->nblights; i++)
|
|
|
|
{
|
|
|
|
lighted = _applyDirectLight(status->lights + i, renderer, location, normal, material);
|
2012-01-25 17:31:36 +00:00
|
|
|
result.r += lighted.r;
|
|
|
|
result.g += lighted.g;
|
|
|
|
result.b += lighted.b;
|
2012-01-22 22:06:11 +00:00
|
|
|
}
|
2012-05-06 10:13:34 +00:00
|
|
|
|
2011-12-10 13:25:22 +00:00
|
|
|
return result;
|
2012-01-22 22:06:11 +00:00
|
|
|
}
|
2012-05-06 10:13:34 +00:00
|
|
|
|
|
|
|
Color lightingApplyToSurface(LightingDefinition* definition, Renderer* renderer, Vector3 location, Vector3 normal, SurfaceMaterial material)
|
|
|
|
{
|
|
|
|
LightStatus status;
|
|
|
|
|
|
|
|
lightingGetStatus(definition, renderer, location, &status);
|
|
|
|
return lightingApplyStatusToSurface(renderer, &status, location, normal, material);
|
|
|
|
}
|