clouds_walking: Added entry refinement
This commit is contained in:
parent
a484479fb7
commit
1c0c93479e
3 changed files with 107 additions and 14 deletions
|
@ -36,6 +36,7 @@ struct CloudsWalker
|
|||
double max_length;
|
||||
double step_size;
|
||||
|
||||
int started;
|
||||
CloudWalkerStepInfo last_segment;
|
||||
|
||||
CloudWalkingNextAction next_action;
|
||||
|
@ -107,10 +108,9 @@ CloudsWalker* cloudsCreateWalker(Renderer* renderer, CloudsLayerDefinition* laye
|
|||
result->cursor = 0.0;
|
||||
result->step_size = 1.0;
|
||||
|
||||
result->started = 0;
|
||||
result->last_segment.renderer = renderer;
|
||||
result->last_segment.layer = layer;
|
||||
result->last_segment.walked_distance = 0.0;
|
||||
result->last_segment.end = start;
|
||||
|
||||
result->next_action.order = CLOUD_WALKING_CONTINUE;
|
||||
|
||||
|
@ -128,8 +128,64 @@ void cloudsSetStepSize(CloudsWalker* walker, double step)
|
|||
walker->step_size = step;
|
||||
}
|
||||
|
||||
static void _getPoint(CloudsWalker* walker, double cursor, CloudWalkerPoint* out_point)
|
||||
{
|
||||
out_point->distance_from_start = cursor;
|
||||
out_point->location = v3Add(walker->start, v3Scale(walker->diff, out_point->distance_from_start / walker->max_length));
|
||||
|
||||
Renderer* renderer = walker->last_segment.renderer;
|
||||
CloudsLayerDefinition* layer = walker->last_segment.layer;
|
||||
out_point->global_density = renderer->clouds->getLayerDensity(renderer, layer, out_point->location);
|
||||
}
|
||||
|
||||
static void _refineSegment(CloudsWalker* walker, double start_cursor, double start_density, double end_cursor, double end_density, double precision, CloudWalkerPoint* result)
|
||||
{
|
||||
CloudWalkerPoint middle;
|
||||
|
||||
_getPoint(walker, (start_cursor + end_cursor) / 2.0, &middle);
|
||||
|
||||
if (start_density == 0.0)
|
||||
{
|
||||
/* Looking for entry */
|
||||
if (middle.global_density == 0.0)
|
||||
{
|
||||
_refineSegment(walker, middle.distance_from_start, middle.global_density, end_cursor, end_density, precision, result);
|
||||
}
|
||||
else if (middle.distance_from_start - start_cursor > precision)
|
||||
{
|
||||
_refineSegment(walker, start_cursor, start_density, middle.distance_from_start, middle.global_density, precision, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
*result = middle;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Looking for exit */
|
||||
if (middle.global_density == 0.0)
|
||||
{
|
||||
_refineSegment(walker, start_cursor, start_density, middle.distance_from_start, middle.global_density, precision, result);
|
||||
}
|
||||
else if (end_cursor - middle.distance_from_start > precision)
|
||||
{
|
||||
_refineSegment(walker, middle.distance_from_start, middle.global_density, end_cursor, end_density, precision, result);
|
||||
}
|
||||
else
|
||||
{
|
||||
*result = middle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int cloudsWalkerPerformStep(CloudsWalker* walker)
|
||||
{
|
||||
if (!walker->started)
|
||||
{
|
||||
_getPoint(walker, 0.0, &walker->last_segment.end);
|
||||
walker->started = 1;
|
||||
}
|
||||
|
||||
if (walker->next_action.order == CLOUD_WALKING_STOP || walker->cursor >= walker->max_length)
|
||||
{
|
||||
walker->next_action.order = CLOUD_WALKING_STOP;
|
||||
|
@ -139,15 +195,28 @@ int cloudsWalkerPerformStep(CloudsWalker* walker)
|
|||
{
|
||||
/* TODO Limit to end */
|
||||
walker->last_segment.start = walker->last_segment.end;
|
||||
walker->last_segment.walked_distance = walker->cursor;
|
||||
|
||||
walker->cursor += walker->step_size;
|
||||
|
||||
walker->last_segment.end = v3Add(walker->start, v3Scale(walker->diff, walker->cursor / walker->max_length));
|
||||
_getPoint(walker, walker->cursor, &walker->last_segment.end);
|
||||
walker->last_segment.length = walker->step_size;
|
||||
|
||||
return 1;
|
||||
}
|
||||
else if (walker->next_action.order == CLOUD_WALKING_REFINE)
|
||||
{
|
||||
/* Refine segment with dichotomy */
|
||||
_refineSegment(walker,
|
||||
walker->last_segment.start.distance_from_start,
|
||||
walker->last_segment.start.global_density,
|
||||
walker->last_segment.end.distance_from_start,
|
||||
walker->last_segment.end.global_density,
|
||||
walker->next_action.precision,
|
||||
&walker->last_segment.start);
|
||||
walker->last_segment.length = walker->last_segment.end.distance_from_start - walker->last_segment.start.distance_from_start;
|
||||
walker->next_action.order = CLOUD_WALKING_CONTINUE;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* TODO */
|
||||
|
|
|
@ -13,6 +13,13 @@ extern "C"
|
|||
{
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
double distance_from_start;
|
||||
Vector3 location;
|
||||
double global_density;
|
||||
} CloudWalkerPoint;
|
||||
|
||||
/**
|
||||
* Information on a segment yielded by walking.
|
||||
*/
|
||||
|
@ -21,9 +28,8 @@ typedef struct
|
|||
Renderer* renderer;
|
||||
CloudsLayerDefinition* layer;
|
||||
|
||||
double walked_distance;
|
||||
Vector3 start;
|
||||
Vector3 end;
|
||||
CloudWalkerPoint start;
|
||||
CloudWalkerPoint end;
|
||||
double length;
|
||||
|
||||
/*int refined;
|
||||
|
@ -91,6 +97,9 @@ void cloudsWalkerOrderStop(CloudsWalker* walker);
|
|||
/**
|
||||
* Order the walker to refine the search for cloud entry or exit.
|
||||
*
|
||||
* The refinement will next yield a shorter version of the segment, containing only the cloud-inside portion, with a
|
||||
* tolerance fixed by precision. For an entry point, this will discard the part before cloud entry. For en exit point,
|
||||
* the portion after this point will be part of the next step, as normal walking resumes.
|
||||
* @param walker The walker to use
|
||||
* @param precision Precision wanted for the refinement
|
||||
*/
|
||||
|
|
|
@ -224,23 +224,38 @@ START_TEST(test_clouds_walking)
|
|||
result = cloudsWalkerPerformStep(walker);
|
||||
segment = cloudsWalkerGetLastSegment(walker);
|
||||
ck_assert_int_eq(result, 1);
|
||||
ck_assert_double_eq(segment->walked_distance, 0.0);
|
||||
ck_assert_vector_values(segment->start, -0.4, 0.0, 0.0);
|
||||
ck_assert_vector_values(segment->end, -0.1, 0.0, 0.0);
|
||||
ck_assert_double_eq(segment->length, 0.3);
|
||||
ck_assert_double_eq(segment->start.distance_from_start, 0.0);
|
||||
ck_assert_vector_values(segment->start.location, -0.4, 0.0, 0.0);
|
||||
ck_assert_double_eq(segment->start.global_density, 0.0);
|
||||
ck_assert_double_eq(segment->end.distance_from_start, 0.3);
|
||||
ck_assert_vector_values(segment->end.location, -0.1, 0.0, 0.0);
|
||||
ck_assert_double_eq(segment->end.global_density, 0.0);
|
||||
|
||||
/* Second step */
|
||||
result = cloudsWalkerPerformStep(walker);
|
||||
segment = cloudsWalkerGetLastSegment(walker);
|
||||
ck_assert_int_eq(result, 1);
|
||||
ck_assert_double_eq(segment->walked_distance, 0.3);
|
||||
ck_assert_vector_values(segment->start, -0.1, 0.0, 0.0);
|
||||
ck_assert_vector_values(segment->end, 0.2, 0.0, 0.0);
|
||||
ck_assert_double_eq(segment->length, 0.3);
|
||||
ck_assert_double_eq(segment->start.distance_from_start, 0.3);
|
||||
ck_assert_vector_values(segment->start.location, -0.1, 0.0, 0.0);
|
||||
ck_assert_double_eq(segment->start.global_density, 0.0);
|
||||
ck_assert_double_eq(segment->end.distance_from_start, 0.6);
|
||||
ck_assert_vector_values(segment->end.location, 0.2, 0.0, 0.0);
|
||||
ck_assert_double_gt(segment->end.global_density, 0.9);
|
||||
|
||||
/* Order to refine second step around the entry point */
|
||||
cloudsWalkerOrderRefine(walker, 0.01);
|
||||
/* TODO */
|
||||
result = cloudsWalkerPerformStep(walker);
|
||||
segment = cloudsWalkerGetLastSegment(walker);
|
||||
ck_assert_int_eq(result, 1);
|
||||
ck_assert_double_in_range(segment->length, 0.19, 0.21);
|
||||
ck_assert_double_in_range(segment->start.distance_from_start, 0.39, 0.41);
|
||||
ck_assert_double_in_range(segment->start.location.x, -0.01, 0.01);
|
||||
/* TODO Check segment->start.global_density */
|
||||
ck_assert_double_eq(segment->end.distance_from_start, 0.6);
|
||||
ck_assert_vector_values(segment->end.location, 0.2, 0.0, 0.0);
|
||||
ck_assert_double_gt(segment->end.global_density, 0.9);
|
||||
|
||||
/* Clean up */
|
||||
cloudsDeleteWalker(walker);
|
||||
|
|
Loading…
Reference in a new issue