#include "private.h" #include #include #include #include "../tools.h" #include "../renderer.h" #include "../system.h" #define MAX_SKYDOME_LIGHTS 100 static int _inited = 0; /******************** Definition ********************/ static void _validateDefinition(AtmosphereDefinition* definition) { if (definition->hour < 0) { definition->hour = 0; } if (definition->hour > 23) { definition->hour = 23; } if (definition->minute < 0) { definition->minute = 0; } if (definition->minute > 59) { definition->minute = 59; } definition->_daytime = (double)definition->hour / 24.0 + (double)definition->minute / 1440.0; } static AtmosphereDefinition* _createDefinition() { AtmosphereDefinition* result; /* TODO Find a better place for this */ if (!_inited) { _inited = 1; brunetonInit(); } result = malloc(sizeof(AtmosphereDefinition)); atmosphereAutoPreset(result, ATMOSPHERE_PRESET_CLEAR_DAY); return result; } static void _deleteDefinition(AtmosphereDefinition* definition) { free(definition); } static void _copyDefinition(AtmosphereDefinition* source, AtmosphereDefinition* destination) { destination->model = source->model; destination->hour = source->hour; destination->minute = source->minute; destination->sun_color = source->sun_color; destination->sun_radius = source->sun_radius; destination->dome_lighting = source->dome_lighting; destination->humidity = source->humidity; _validateDefinition(destination); } static void _saveDefinition(PackStream* stream, AtmosphereDefinition* definition) { packWriteInt(stream, (int*)&definition->model); packWriteInt(stream, &definition->hour); packWriteInt(stream, &definition->minute); colorSave(stream, &definition->sun_color); packWriteDouble(stream, &definition->sun_radius); packWriteDouble(stream, &definition->dome_lighting); packWriteDouble(stream, &definition->humidity); } static void _loadDefinition(PackStream* stream, AtmosphereDefinition* definition) { packReadInt(stream, (int*)&definition->model); packReadInt(stream, &definition->hour); packReadInt(stream, &definition->minute); colorLoad(stream, &definition->sun_color); packReadDouble(stream, &definition->sun_radius); packReadDouble(stream, &definition->dome_lighting); packReadDouble(stream, &definition->humidity); _validateDefinition(definition); } StandardDefinition AtmosphereDefinitionClass = { (FuncObjectCreate)_createDefinition, (FuncObjectDelete)_deleteDefinition, (FuncObjectCopy)_copyDefinition, (FuncObjectValidate)_validateDefinition, (FuncObjectSave)_saveDefinition, (FuncObjectLoad)_loadDefinition }; /******************** Binding ********************/ static Color _fakeApplyAerialPerspective(Renderer* renderer, Vector3 location, Color base) { UNUSED(renderer); UNUSED(location); return base; } static Color _fakeGetSkyColor(Renderer* renderer, Vector3 direction) { UNUSED(renderer); UNUSED(direction); return COLOR_WHITE; } static Color _getSkyColor(Renderer* renderer, Vector3 direction) { AtmosphereDefinition* definition; Vector3 sun_direction, sun_position; Color sky_color, sun_color; definition = renderer->atmosphere->definition; sun_direction = renderer->atmosphere->getSunDirection(renderer); direction = v3Normalize(direction); sun_position = v3Scale(sun_direction, SUN_DISTANCE_SCALED); /* Get base scattering*/ switch (definition->model) { case ATMOSPHERE_MODEL_BRUNETON: sky_color = brunetonGetSkyColor(definition, renderer->camera_location, direction, sun_position); break; case ATMOSPHERE_MODEL_PREETHAM: sky_color = preethamGetSkyColor(definition, renderer->camera_location, direction, sun_position); break; default: sky_color = COLOR_BLUE; } /* Get sun shape */ double sun_radius = definition->sun_radius * SUN_RADIUS_SCALED; Vector3 hit1, hit2; int hits = euclidRayIntersectSphere(renderer->camera_location, direction, sun_position, sun_radius, &hit1, &hit2); if (hits > 1) { 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); return sky_color; } } else { return sky_color; } } static Vector3 _getSunDirection(Renderer* renderer) { Vector3 result; double sun_angle = (renderer->atmosphere->definition->_daytime + 0.75) * M_PI * 2.0; result.x = cos(sun_angle); result.y = sin(sun_angle); result.z = 0.0; return result; } static void _fakeGetLightingStatus(Renderer* renderer, LightStatus* status, Vector3 normal, int opaque) { LightDefinition light; UNUSED(renderer); UNUSED(normal); UNUSED(opaque); 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); } /******************** Renderer ********************/ static AtmosphereRenderer* _createRenderer() { AtmosphereRenderer* result; result = malloc(sizeof(AtmosphereRenderer)); result->definition = AtmosphereDefinitionClass.create(); result->getLightingStatus = _fakeGetLightingStatus; result->getSunDirection = _getSunDirection; result->applyAerialPerspective = _fakeApplyAerialPerspective; result->getSkyColor = _fakeGetSkyColor; return result; } static void _deleteRenderer(AtmosphereRenderer* renderer) { AtmosphereDefinitionClass.destroy(renderer->definition); free(renderer); } static void _bindRenderer(Renderer* renderer, AtmosphereDefinition* definition) { AtmosphereDefinitionClass.copy(definition, renderer->atmosphere->definition); renderer->atmosphere->getSkyColor = _getSkyColor; switch (definition->model) { case ATMOSPHERE_MODEL_BRUNETON: renderer->atmosphere->applyAerialPerspective = brunetonApplyAerialPerspective; renderer->atmosphere->getLightingStatus = brunetonGetLightingStatus; break; default: renderer->atmosphere->applyAerialPerspective = basicApplyAerialPerspective; renderer->atmosphere->getLightingStatus = basicGetLightingStatus; } } StandardRenderer AtmosphereRendererClass = { (FuncObjectCreate)_createRenderer, (FuncObjectDelete)_deleteRenderer, (FuncObjectBind)_bindRenderer };