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 max_length;
|
||||||
double step_size;
|
double step_size;
|
||||||
|
|
||||||
|
int started;
|
||||||
CloudWalkerStepInfo last_segment;
|
CloudWalkerStepInfo last_segment;
|
||||||
|
|
||||||
CloudWalkingNextAction next_action;
|
CloudWalkingNextAction next_action;
|
||||||
|
@ -107,10 +108,9 @@ CloudsWalker* cloudsCreateWalker(Renderer* renderer, CloudsLayerDefinition* laye
|
||||||
result->cursor = 0.0;
|
result->cursor = 0.0;
|
||||||
result->step_size = 1.0;
|
result->step_size = 1.0;
|
||||||
|
|
||||||
|
result->started = 0;
|
||||||
result->last_segment.renderer = renderer;
|
result->last_segment.renderer = renderer;
|
||||||
result->last_segment.layer = layer;
|
result->last_segment.layer = layer;
|
||||||
result->last_segment.walked_distance = 0.0;
|
|
||||||
result->last_segment.end = start;
|
|
||||||
|
|
||||||
result->next_action.order = CLOUD_WALKING_CONTINUE;
|
result->next_action.order = CLOUD_WALKING_CONTINUE;
|
||||||
|
|
||||||
|
@ -128,8 +128,64 @@ void cloudsSetStepSize(CloudsWalker* walker, double step)
|
||||||
walker->step_size = 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)
|
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)
|
if (walker->next_action.order == CLOUD_WALKING_STOP || walker->cursor >= walker->max_length)
|
||||||
{
|
{
|
||||||
walker->next_action.order = CLOUD_WALKING_STOP;
|
walker->next_action.order = CLOUD_WALKING_STOP;
|
||||||
|
@ -139,15 +195,28 @@ int cloudsWalkerPerformStep(CloudsWalker* walker)
|
||||||
{
|
{
|
||||||
/* TODO Limit to end */
|
/* TODO Limit to end */
|
||||||
walker->last_segment.start = walker->last_segment.end;
|
walker->last_segment.start = walker->last_segment.end;
|
||||||
walker->last_segment.walked_distance = walker->cursor;
|
|
||||||
|
|
||||||
walker->cursor += walker->step_size;
|
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;
|
walker->last_segment.length = walker->step_size;
|
||||||
|
|
||||||
return 1;
|
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
|
else
|
||||||
{
|
{
|
||||||
/* TODO */
|
/* TODO */
|
||||||
|
|
|
@ -13,6 +13,13 @@ extern "C"
|
||||||
{
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
double distance_from_start;
|
||||||
|
Vector3 location;
|
||||||
|
double global_density;
|
||||||
|
} CloudWalkerPoint;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Information on a segment yielded by walking.
|
* Information on a segment yielded by walking.
|
||||||
*/
|
*/
|
||||||
|
@ -21,9 +28,8 @@ typedef struct
|
||||||
Renderer* renderer;
|
Renderer* renderer;
|
||||||
CloudsLayerDefinition* layer;
|
CloudsLayerDefinition* layer;
|
||||||
|
|
||||||
double walked_distance;
|
CloudWalkerPoint start;
|
||||||
Vector3 start;
|
CloudWalkerPoint end;
|
||||||
Vector3 end;
|
|
||||||
double length;
|
double length;
|
||||||
|
|
||||||
/*int refined;
|
/*int refined;
|
||||||
|
@ -91,6 +97,9 @@ void cloudsWalkerOrderStop(CloudsWalker* walker);
|
||||||
/**
|
/**
|
||||||
* Order the walker to refine the search for cloud entry or exit.
|
* 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 walker The walker to use
|
||||||
* @param precision Precision wanted for the refinement
|
* @param precision Precision wanted for the refinement
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -224,23 +224,38 @@ START_TEST(test_clouds_walking)
|
||||||
result = cloudsWalkerPerformStep(walker);
|
result = cloudsWalkerPerformStep(walker);
|
||||||
segment = cloudsWalkerGetLastSegment(walker);
|
segment = cloudsWalkerGetLastSegment(walker);
|
||||||
ck_assert_int_eq(result, 1);
|
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->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 */
|
/* Second step */
|
||||||
result = cloudsWalkerPerformStep(walker);
|
result = cloudsWalkerPerformStep(walker);
|
||||||
segment = cloudsWalkerGetLastSegment(walker);
|
segment = cloudsWalkerGetLastSegment(walker);
|
||||||
ck_assert_int_eq(result, 1);
|
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->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 */
|
/* Order to refine second step around the entry point */
|
||||||
cloudsWalkerOrderRefine(walker, 0.01);
|
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 */
|
/* Clean up */
|
||||||
cloudsDeleteWalker(walker);
|
cloudsDeleteWalker(walker);
|
||||||
|
|
Loading…
Reference in a new issue