clouds_walking: Added iterator system for walking

This commit is contained in:
Michaël Lemaire 2013-05-29 22:01:09 +02:00 committed by Michael Lemaire
parent 6e8e1bc307
commit a484479fb7
3 changed files with 120 additions and 5 deletions

View file

@ -23,6 +23,24 @@ typedef struct
int max_segments; int max_segments;
} CloudWalkingNextAction; } CloudWalkingNextAction;
/*
* Private structure for the walker.
*/
struct CloudsWalker
{
Vector3 start;
Vector3 end;
Vector3 diff;
double cursor;
double max_length;
double step_size;
CloudWalkerStepInfo last_segment;
CloudWalkingNextAction next_action;
};
int cloudsOptimizeWalkingBounds(CloudsLayerDefinition* layer, Vector3* start, Vector3* end) int cloudsOptimizeWalkingBounds(CloudsLayerDefinition* layer, Vector3* start, Vector3* end)
{ {
@ -78,32 +96,91 @@ int cloudsOptimizeWalkingBounds(CloudsLayerDefinition* layer, Vector3* start, Ve
CloudsWalker* cloudsCreateWalker(Renderer* renderer, CloudsLayerDefinition* layer, Vector3 start, Vector3 end) CloudsWalker* cloudsCreateWalker(Renderer* renderer, CloudsLayerDefinition* layer, Vector3 start, Vector3 end)
{ {
CloudsWalker* result;
result = (CloudsWalker*)malloc(sizeof (CloudsWalker));
result->start = start;
result->end = end;
result->diff = v3Sub(end, start);
result->max_length = v3Norm(result->diff);
result->cursor = 0.0;
result->step_size = 1.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;
return result;
} }
void cloudsDeleteWalker(CloudsWalker* walker) void cloudsDeleteWalker(CloudsWalker* walker)
{ {
free(walker);
} }
void cloudsWalkerPerformStep(CloudsWalker* walker) void cloudsSetStepSize(CloudsWalker* walker, double step)
{ {
/* TODO Negative step => automatic */
walker->step_size = step;
}
int cloudsWalkerPerformStep(CloudsWalker* walker)
{
if (walker->next_action.order == CLOUD_WALKING_STOP || walker->cursor >= walker->max_length)
{
walker->next_action.order = CLOUD_WALKING_STOP;
return 0;
}
else if (walker->next_action.order == CLOUD_WALKING_CONTINUE)
{
/* 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));
walker->last_segment.length = walker->step_size;
return 1;
}
else
{
/* TODO */
return 0;
}
} }
void cloudsWalkerOrderStop(CloudsWalker* walker) void cloudsWalkerOrderStop(CloudsWalker* walker)
{ {
walker->next_action.order = CLOUD_WALKING_STOP;
} }
void cloudsWalkerOrderRefine(CloudsWalker* walker, double precision) void cloudsWalkerOrderRefine(CloudsWalker* walker, double precision)
{ {
walker->next_action.order = CLOUD_WALKING_REFINE;
walker->next_action.precision = precision;
} }
void cloudsWalkerOrderSubdivide(CloudsWalker* walker, double max_segments) void cloudsWalkerOrderSubdivide(CloudsWalker* walker, double max_segments)
{ {
walker->next_action.order = CLOUD_WALKING_SUBDIVIDE;
walker->next_action.max_segments = max_segments;
} }
CloudWalkerStepInfo* cloudsWalkerGetLastSegment(CloudsWalker* walker) CloudWalkerStepInfo* cloudsWalkerGetLastSegment(CloudsWalker* walker)
{ {
return &walker->last_segment;
} }
void cloudsStartWalking(CloudsWalker* walker, FuncCloudsWalkingCallback callback, void* data) void cloudsStartWalking(CloudsWalker* walker, FuncCloudsWalkingCallback callback, void* data)
{ {
while (cloudsWalkerPerformStep(walker))
{
callback(walker);
}
} }

View file

@ -26,9 +26,9 @@ typedef struct
Vector3 end; Vector3 end;
double length; double length;
int refined; /*int refined;
int subdivision_level; int subdivision_level;
double precision_asked; double precision_asked;*/
void* data; void* data;
} CloudWalkerStepInfo; } CloudWalkerStepInfo;
@ -65,12 +65,21 @@ CloudsWalker* cloudsCreateWalker(Renderer* renderer, CloudsLayerDefinition* laye
*/ */
void cloudsDeleteWalker(CloudsWalker* walker); void cloudsDeleteWalker(CloudsWalker* walker);
/**
* Define the segment size for next steps.
*
* @param walker The walker to configure
* @param step The step length, negative for automatic
*/
void cloudsSetStepSize(CloudsWalker* walker, double step);
/** /**
* Perform a single step. * Perform a single step.
* *
* @param walker The walker to use * @param walker The walker to use
* @return 1 to continue the loop, 0 to stop
*/ */
void cloudsWalkerPerformStep(CloudsWalker* walker); int cloudsWalkerPerformStep(CloudsWalker* walker);
/** /**
* Order the walker to stop. * Order the walker to stop.

View file

@ -202,6 +202,7 @@ static double _getLayerDensitySinX(Renderer* renderer, CloudsLayerDefinition* la
START_TEST(test_clouds_walking) START_TEST(test_clouds_walking)
{ {
/* Init */
CloudsLayerDefinition* layer; CloudsLayerDefinition* layer;
layer = cloudsGetLayerType().callback_create(); layer = cloudsGetLayerType().callback_create();
layer->lower_altitude = -1.0; layer->lower_altitude = -1.0;
@ -214,7 +215,35 @@ START_TEST(test_clouds_walking)
renderer->render_quality = 8; renderer->render_quality = 8;
renderer->clouds->getLayerDensity = _getLayerDensitySinX; renderer->clouds->getLayerDensity = _getLayerDensitySinX;
// TODO CloudsWalker* walker = cloudsCreateWalker(renderer, layer, v3(-0.4, 0.0, 0.0), v3(10.0, 0.0, 0.0));
CloudWalkerStepInfo* segment;
int result;
/* First step */
cloudsSetStepSize(walker, 0.3);
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);
/* 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);
/* Order to refine second step around the entry point */
cloudsWalkerOrderRefine(walker, 0.01);
/* TODO */
/* Clean up */
cloudsDeleteWalker(walker);
cloudsGetLayerType().callback_delete(layer); cloudsGetLayerType().callback_delete(layer);
rendererDelete(renderer); rendererDelete(renderer);