2015-10-18 15:26:19 +00:00
|
|
|
#include "VegetationRenderer.h"
|
|
|
|
|
|
|
|
#include "VegetationModelRenderer.h"
|
|
|
|
#include "RayCastingResult.h"
|
|
|
|
#include "SpaceGridIterator.h"
|
|
|
|
#include "SpaceSegment.h"
|
|
|
|
#include "VegetationInstance.h"
|
|
|
|
#include "SoftwareRenderer.h"
|
|
|
|
#include "Scenery.h"
|
|
|
|
#include "TerrainRenderer.h"
|
|
|
|
#include "VegetationDefinition.h"
|
2015-10-18 20:15:19 +00:00
|
|
|
#include "VegetationLayerDefinition.h"
|
|
|
|
#include "VegetationPresenceDefinition.h"
|
|
|
|
#include "VegetationInstance.h"
|
2015-10-18 15:26:19 +00:00
|
|
|
#include "VegetationResult.h"
|
|
|
|
#include "LightComponent.h"
|
|
|
|
|
2015-10-18 20:15:19 +00:00
|
|
|
/**
|
|
|
|
* Grid iterator to collect instances of a layer, in small squares.
|
|
|
|
*/
|
2015-10-18 15:26:19 +00:00
|
|
|
class VegetationGridIterator: public SpaceGridIterator
|
|
|
|
{
|
|
|
|
public:
|
2015-10-18 20:15:19 +00:00
|
|
|
VegetationGridIterator(const SpaceSegment &segment, VegetationRenderer *renderer, VegetationLayerDefinition *layer, bool only_hit):
|
|
|
|
segment(segment), renderer(renderer), layer(layer), only_hit(only_hit)
|
2015-10-18 15:26:19 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
inline const RayCastingResult &getResult() const {return result;}
|
|
|
|
|
|
|
|
virtual bool onCell(int x, int, int z) override
|
|
|
|
{
|
2015-10-18 20:15:19 +00:00
|
|
|
std::vector<VegetationInstance> instances;
|
|
|
|
|
|
|
|
layer->getPresence()->collectInstances(&instances, *layer->getModel(), x - 0.5, z - 0.5, x + 0.5, z + 0.5);
|
|
|
|
|
|
|
|
for (auto &instance: instances)
|
|
|
|
{
|
|
|
|
result = renderer->renderInstance(segment, instance, only_hit);
|
|
|
|
if (result.hit)
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
2015-10-18 15:26:19 +00:00
|
|
|
}
|
|
|
|
private:
|
|
|
|
const SpaceSegment &segment;
|
|
|
|
VegetationRenderer *renderer;
|
2015-10-18 20:15:19 +00:00
|
|
|
VegetationLayerDefinition *layer;
|
2015-10-18 15:26:19 +00:00
|
|
|
RayCastingResult result;
|
|
|
|
bool only_hit;
|
|
|
|
};
|
|
|
|
|
|
|
|
VegetationRenderer::VegetationRenderer(SoftwareRenderer *parent):
|
|
|
|
parent(parent)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2015-10-18 15:35:42 +00:00
|
|
|
void VegetationRenderer::setEnabled(bool enabled)
|
|
|
|
{
|
|
|
|
this->enabled = enabled;
|
|
|
|
}
|
|
|
|
|
2015-10-18 20:15:19 +00:00
|
|
|
RayCastingResult VegetationRenderer::renderInstance(const SpaceSegment &segment, const VegetationInstance &instance, bool only_hit, bool displaced)
|
2015-10-18 15:26:19 +00:00
|
|
|
{
|
2015-10-18 20:15:19 +00:00
|
|
|
if (!displaced)
|
|
|
|
{
|
|
|
|
// Recursive call on displaced instance
|
|
|
|
const Vector3 &base = instance.getBase();
|
|
|
|
TerrainRenderer::TerrainResult terrain = parent->getTerrainRenderer()->getResult(base.x, base.z, true, true);
|
|
|
|
VegetationInstance displaced_instance = instance.displace(terrain.location, terrain.normal);
|
|
|
|
return renderInstance(segment, displaced_instance, only_hit, true);
|
|
|
|
}
|
2015-10-18 15:26:19 +00:00
|
|
|
|
2015-10-18 20:15:19 +00:00
|
|
|
RayCastingResult final;
|
2015-10-18 15:26:19 +00:00
|
|
|
VegetationModelRenderer model_renderer(parent, &instance.getModel());
|
|
|
|
SpaceSegment scaled_segment(segment.getStart().sub(instance.getBase()).scale(1.0 / instance.getSize()),
|
|
|
|
segment.getEnd().sub(instance.getBase()).scale(1.0 / instance.getSize()));
|
|
|
|
VegetationResult result = model_renderer.getResult(scaled_segment, only_hit);
|
|
|
|
|
|
|
|
final.hit = result.isHit();
|
|
|
|
|
|
|
|
if (final.hit and not only_hit)
|
|
|
|
{
|
|
|
|
Vector3 location = result.getLocation().scale(instance.getSize()).add(instance.getBase());
|
|
|
|
final.hit_color = parent->applyLightingToSurface(location, result.getNormal(), result.getMaterial());
|
|
|
|
final.hit_color = parent->applyMediumTraversal(location, final.hit_color);
|
|
|
|
final.hit_location = result.getLocation();
|
|
|
|
}
|
|
|
|
|
|
|
|
return final;
|
|
|
|
}
|
|
|
|
|
|
|
|
RayCastingResult VegetationRenderer::getResult(const SpaceSegment &segment, bool only_hit)
|
|
|
|
{
|
2015-10-18 15:35:42 +00:00
|
|
|
if (enabled)
|
2015-10-18 15:26:19 +00:00
|
|
|
{
|
2015-10-18 20:15:19 +00:00
|
|
|
VegetationDefinition *vegetation = parent->getScenery()->getVegetation();
|
|
|
|
int n = vegetation->count();
|
|
|
|
// TODO Don't stop at first layer, find the nearest hit
|
|
|
|
for (int i = 0; i < n; i++)
|
2015-10-18 15:35:42 +00:00
|
|
|
{
|
2015-10-18 20:15:19 +00:00
|
|
|
// Find instances potentially crossing the segment
|
|
|
|
VegetationGridIterator it(segment, this, vegetation->getVegetationLayer(i), only_hit);
|
|
|
|
if (not segment.projectedOnYPlane().iterateOnGrid(it))
|
|
|
|
{
|
|
|
|
return it.getResult();
|
|
|
|
}
|
2015-10-18 15:35:42 +00:00
|
|
|
}
|
2015-10-18 20:15:19 +00:00
|
|
|
return RayCastingResult();
|
2015-10-18 15:26:19 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return RayCastingResult();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool VegetationRenderer::applyLightFilter(LightComponent &light, const Vector3 &at)
|
|
|
|
{
|
2015-10-18 15:35:42 +00:00
|
|
|
if (enabled)
|
2015-10-18 15:26:19 +00:00
|
|
|
{
|
2015-10-18 15:35:42 +00:00
|
|
|
// Get segment to iterate
|
|
|
|
SpaceSegment segment(at, at.add(light.direction.scale(-1.0 * parent->render_quality)));
|
|
|
|
if (getResult(segment, true).hit)
|
|
|
|
{
|
|
|
|
light.color = COLOR_BLACK;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
2015-10-18 15:26:19 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|