2012-12-02 11:08:56 +00:00
|
|
|
#include "private.h"
|
2012-11-25 21:53:01 +00:00
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "../tools.h"
|
|
|
|
#include "../renderer.h"
|
|
|
|
#include "../system.h"
|
|
|
|
|
2013-03-11 16:57:26 +00:00
|
|
|
/******************** Fake ********************/
|
|
|
|
static Color _fakeApplyAerialPerspective(Renderer* renderer, Vector3 location, Color base)
|
|
|
|
{
|
|
|
|
UNUSED(renderer);
|
|
|
|
UNUSED(location);
|
|
|
|
return base;
|
|
|
|
}
|
2012-11-25 21:53:01 +00:00
|
|
|
|
2013-03-11 16:57:26 +00:00
|
|
|
static Color _fakeGetSkyColor(Renderer* renderer, Vector3 direction)
|
|
|
|
{
|
|
|
|
UNUSED(renderer);
|
|
|
|
UNUSED(direction);
|
|
|
|
return COLOR_WHITE;
|
|
|
|
}
|
2012-12-15 10:14:57 +00:00
|
|
|
|
2013-03-11 16:57:26 +00:00
|
|
|
static void _fakeGetLightingStatus(Renderer* renderer, LightStatus* status, Vector3 normal, int opaque)
|
2012-11-25 21:53:01 +00:00
|
|
|
{
|
2013-03-11 16:57:26 +00:00
|
|
|
LightDefinition light;
|
|
|
|
|
|
|
|
UNUSED(renderer);
|
|
|
|
UNUSED(normal);
|
|
|
|
UNUSED(opaque);
|
2012-12-24 15:15:40 +00:00
|
|
|
|
2013-03-11 16:57:26 +00:00
|
|
|
light.color.r = 0.8;
|
|
|
|
light.color.g = 0.8;
|
|
|
|
light.color.b = 0.8;
|
|
|
|
light.direction.x = -0.7;
|
|
|
|
light.direction.y = -0.7;
|
|
|
|
light.direction.z = 0.7;
|
|
|
|
light.altered = 0;
|
|
|
|
light.reflection = 0.0;
|
|
|
|
lightingPushLight(status, &light);
|
|
|
|
light.color.r = 0.3;
|
|
|
|
light.color.g = 0.31;
|
|
|
|
light.color.b = 0.34;
|
|
|
|
light.direction.x = 0.7;
|
|
|
|
light.direction.y = -0.7;
|
|
|
|
light.direction.z = -0.7;
|
|
|
|
light.altered = 0;
|
|
|
|
light.reflection = 0.0;
|
|
|
|
lightingPushLight(status, &light);
|
2012-11-25 21:53:01 +00:00
|
|
|
}
|
|
|
|
|
2013-03-11 16:57:26 +00:00
|
|
|
/******************** Real ********************/
|
|
|
|
static inline Color _applyWeatherEffects(AtmosphereDefinition* definition, Color base, Color scattered, double distance)
|
2012-11-25 21:53:01 +00:00
|
|
|
{
|
2013-03-11 16:57:26 +00:00
|
|
|
double max_power = colorGetPower(&scattered);
|
2012-11-25 21:53:01 +00:00
|
|
|
|
2013-03-11 16:57:26 +00:00
|
|
|
UNUSED(base);
|
|
|
|
|
|
|
|
if (distance > 100.0)
|
2012-12-15 10:14:57 +00:00
|
|
|
{
|
2013-03-11 16:57:26 +00:00
|
|
|
distance = 100.0;
|
2012-12-15 10:14:57 +00:00
|
|
|
}
|
2012-12-12 13:21:46 +00:00
|
|
|
|
2013-03-11 16:57:26 +00:00
|
|
|
scattered.r += distance * 0.02 * definition->humidity;
|
|
|
|
scattered.g += distance * 0.02 * definition->humidity;
|
|
|
|
scattered.b += distance * 0.02 * definition->humidity;
|
2012-12-02 11:08:56 +00:00
|
|
|
|
2013-03-11 16:57:26 +00:00
|
|
|
colorLimitPower(&scattered, max_power - max_power * 0.4 * definition->humidity);
|
2012-11-25 21:53:01 +00:00
|
|
|
|
2013-03-11 16:57:26 +00:00
|
|
|
if (definition->humidity > 0.3)
|
|
|
|
{
|
|
|
|
double humidity = (definition->humidity - 0.3) / 0.7;
|
|
|
|
scattered.r += distance * 0.1 * humidity * humidity;
|
|
|
|
scattered.g += distance * 0.1 * humidity * humidity;
|
|
|
|
scattered.b += distance * 0.1 * humidity * humidity;
|
|
|
|
|
|
|
|
colorLimitPower(&scattered, 10.0 - humidity * 4.0);
|
|
|
|
/*scattered.r *= 1.0 - humidity * 0.8;
|
|
|
|
scattered.g *= 1.0 - humidity * 0.8;
|
|
|
|
scattered.b *= 1.0 - humidity * 0.8;*/
|
|
|
|
}
|
2012-11-25 21:53:01 +00:00
|
|
|
|
2013-03-11 16:57:26 +00:00
|
|
|
return scattered;
|
2012-11-25 21:53:01 +00:00
|
|
|
}
|
|
|
|
|
2013-03-11 16:57:26 +00:00
|
|
|
static Color _realApplyAerialPerspective(Renderer* renderer, Vector3 location, Color base)
|
2012-11-25 21:53:01 +00:00
|
|
|
{
|
2013-03-11 16:57:26 +00:00
|
|
|
AtmosphereDefinition* definition = renderer->atmosphere->definition;
|
|
|
|
Color changed;
|
2012-11-25 21:53:01 +00:00
|
|
|
|
2013-03-11 16:57:26 +00:00
|
|
|
/* Get base perspective */
|
|
|
|
switch (definition->model)
|
|
|
|
{
|
|
|
|
case ATMOSPHERE_MODEL_BRUNETON:
|
|
|
|
changed = brunetonApplyAerialPerspective(renderer, location, base);
|
|
|
|
break;
|
|
|
|
case ATMOSPHERE_MODEL_PREETHAM:
|
|
|
|
changed = basicApplyAerialPerspective(renderer, location, base);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
;
|
|
|
|
}
|
2012-11-25 21:53:01 +00:00
|
|
|
|
2013-03-11 16:57:26 +00:00
|
|
|
/* Apply weather effects */
|
|
|
|
changed = _applyWeatherEffects(definition, base, changed, v3Norm(v3Sub(location, renderer->getCameraLocation(renderer, location))));
|
2012-11-25 21:53:01 +00:00
|
|
|
|
2013-03-11 16:57:26 +00:00
|
|
|
return changed;
|
2012-11-25 21:53:01 +00:00
|
|
|
}
|
|
|
|
|
2013-03-11 16:57:26 +00:00
|
|
|
static Color _realGetSkyColor(Renderer* renderer, Vector3 direction)
|
2012-11-25 21:53:01 +00:00
|
|
|
{
|
|
|
|
AtmosphereDefinition* definition;
|
2013-01-31 15:10:11 +00:00
|
|
|
Vector3 sun_direction, sun_position, camera_location;
|
2012-11-25 21:53:01 +00:00
|
|
|
Color sky_color, sun_color;
|
2012-12-02 11:08:56 +00:00
|
|
|
|
2012-11-25 21:53:01 +00:00
|
|
|
definition = renderer->atmosphere->definition;
|
2013-01-31 15:10:11 +00:00
|
|
|
camera_location = renderer->getCameraLocation(renderer, VECTOR_ZERO);
|
2012-12-02 11:08:56 +00:00
|
|
|
|
2012-12-23 22:05:12 +00:00
|
|
|
sun_direction = renderer->atmosphere->getSunDirection(renderer);
|
2012-11-25 21:53:01 +00:00
|
|
|
direction = v3Normalize(direction);
|
2013-01-30 17:00:26 +00:00
|
|
|
sun_position = v3Scale(sun_direction, SUN_DISTANCE_SCALED);
|
2012-11-25 21:53:01 +00:00
|
|
|
|
|
|
|
/* Get base scattering*/
|
|
|
|
switch (definition->model)
|
|
|
|
{
|
|
|
|
case ATMOSPHERE_MODEL_BRUNETON:
|
2013-03-10 19:55:24 +00:00
|
|
|
sky_color = brunetonGetSkyColor(renderer, camera_location, direction, sun_position);
|
2012-11-25 21:53:01 +00:00
|
|
|
break;
|
|
|
|
case ATMOSPHERE_MODEL_PREETHAM:
|
2013-01-31 15:10:11 +00:00
|
|
|
sky_color = preethamGetSkyColor(definition, camera_location, direction, sun_position);
|
2012-11-25 21:53:01 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
sky_color = COLOR_BLUE;
|
|
|
|
}
|
2012-12-02 11:08:56 +00:00
|
|
|
|
2013-01-20 21:17:03 +00:00
|
|
|
/* Get sun shape */
|
2013-02-03 21:18:32 +00:00
|
|
|
if (v3Dot(sun_direction, direction) >= 0)
|
2012-11-25 21:53:01 +00:00
|
|
|
{
|
2013-02-03 21:18:32 +00:00
|
|
|
double sun_radius = definition->sun_radius * SUN_RADIUS_SCALED * 5.0; /* FIXME Why should we multiply by 5 ? */
|
|
|
|
Vector3 hit1, hit2;
|
|
|
|
int hits = euclidRayIntersectSphere(camera_location, direction, sun_position, sun_radius, &hit1, &hit2);
|
|
|
|
if (hits > 1)
|
2012-11-25 21:53:01 +00:00
|
|
|
{
|
2013-02-03 21:18:32 +00:00
|
|
|
double dist = v3Norm(v3Sub(hit2, hit1)) / sun_radius; /* distance between intersection points (relative to radius) */
|
|
|
|
|
|
|
|
sun_color = definition->sun_color;
|
|
|
|
sun_color.r *= 100.0;
|
|
|
|
sun_color.g *= 100.0;
|
|
|
|
sun_color.b *= 100.0;
|
|
|
|
|
|
|
|
if (dist > 0.05)
|
|
|
|
{
|
|
|
|
return sun_color;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sun_color.a = 1.0 - dist / 0.05;
|
|
|
|
colorMask(&sky_color, &sun_color);
|
|
|
|
}
|
2012-11-25 21:53:01 +00:00
|
|
|
}
|
|
|
|
}
|
2013-03-11 16:57:26 +00:00
|
|
|
|
|
|
|
/* TODO Apply weather effects */
|
|
|
|
sky_color = _applyWeatherEffects(definition, COLOR_BLACK, sky_color, SPHERE_SIZE);
|
|
|
|
|
2013-02-03 21:18:32 +00:00
|
|
|
return sky_color;
|
2012-11-25 21:53:01 +00:00
|
|
|
}
|
|
|
|
|
2013-03-11 16:57:26 +00:00
|
|
|
static Vector3 _realGetSunDirection(Renderer* renderer)
|
2012-11-25 21:53:01 +00:00
|
|
|
{
|
|
|
|
Vector3 result;
|
2012-12-24 15:15:40 +00:00
|
|
|
double sun_angle = (renderer->atmosphere->definition->_daytime + 0.75) * M_PI * 2.0;
|
2012-11-25 21:53:01 +00:00
|
|
|
result.x = cos(sun_angle);
|
|
|
|
result.y = sin(sun_angle);
|
|
|
|
result.z = 0.0;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/******************** Renderer ********************/
|
|
|
|
static AtmosphereRenderer* _createRenderer()
|
|
|
|
{
|
|
|
|
AtmosphereRenderer* result;
|
2012-12-02 11:08:56 +00:00
|
|
|
|
2012-11-25 21:53:01 +00:00
|
|
|
result = malloc(sizeof(AtmosphereRenderer));
|
|
|
|
result->definition = AtmosphereDefinitionClass.create();
|
2012-12-02 11:08:56 +00:00
|
|
|
|
2013-01-19 22:42:50 +00:00
|
|
|
result->getLightingStatus = _fakeGetLightingStatus;
|
2013-03-11 16:57:26 +00:00
|
|
|
result->getSunDirection = _realGetSunDirection;
|
2012-11-25 21:53:01 +00:00
|
|
|
result->applyAerialPerspective = _fakeApplyAerialPerspective;
|
|
|
|
result->getSkyColor = _fakeGetSkyColor;
|
2012-12-02 11:08:56 +00:00
|
|
|
|
2012-11-25 21:53:01 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void _deleteRenderer(AtmosphereRenderer* renderer)
|
|
|
|
{
|
|
|
|
AtmosphereDefinitionClass.destroy(renderer->definition);
|
|
|
|
free(renderer);
|
|
|
|
}
|
|
|
|
|
2013-01-20 15:07:45 +00:00
|
|
|
static void _bindRenderer(Renderer* renderer, AtmosphereDefinition* definition)
|
2012-11-25 21:53:01 +00:00
|
|
|
{
|
2013-01-20 15:07:45 +00:00
|
|
|
AtmosphereDefinitionClass.copy(definition, renderer->atmosphere->definition);
|
2012-12-02 11:08:56 +00:00
|
|
|
|
2013-03-11 16:57:26 +00:00
|
|
|
renderer->atmosphere->getSkyColor = _realGetSkyColor;
|
|
|
|
renderer->atmosphere->applyAerialPerspective = _realApplyAerialPerspective;
|
2012-12-02 11:08:56 +00:00
|
|
|
|
|
|
|
switch (definition->model)
|
|
|
|
{
|
2012-12-24 11:24:27 +00:00
|
|
|
case ATMOSPHERE_MODEL_BRUNETON:
|
2013-01-20 21:17:03 +00:00
|
|
|
renderer->atmosphere->getLightingStatus = brunetonGetLightingStatus;
|
2012-12-24 11:24:27 +00:00
|
|
|
break;
|
2012-12-02 11:08:56 +00:00
|
|
|
default:
|
2013-01-20 15:07:45 +00:00
|
|
|
renderer->atmosphere->getLightingStatus = basicGetLightingStatus;
|
2012-12-02 11:08:56 +00:00
|
|
|
}
|
2012-11-25 21:53:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
StandardRenderer AtmosphereRendererClass = {
|
|
|
|
(FuncObjectCreate)_createRenderer,
|
|
|
|
(FuncObjectDelete)_deleteRenderer,
|
|
|
|
(FuncObjectBind)_bindRenderer
|
|
|
|
};
|