diff --git a/src/rendering/clouds/clo_walking.c b/src/rendering/clouds/clo_walking.c index 6c74c7f..5dd6672 100644 --- a/src/rendering/clouds/clo_walking.c +++ b/src/rendering/clouds/clo_walking.c @@ -23,6 +23,24 @@ typedef struct int max_segments; } 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) { @@ -78,32 +96,91 @@ int cloudsOptimizeWalkingBounds(CloudsLayerDefinition* layer, Vector3* start, Ve 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) { + 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) { + walker->next_action.order = CLOUD_WALKING_STOP; } 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) { + walker->next_action.order = CLOUD_WALKING_SUBDIVIDE; + walker->next_action.max_segments = max_segments; } CloudWalkerStepInfo* cloudsWalkerGetLastSegment(CloudsWalker* walker) { + return &walker->last_segment; } void cloudsStartWalking(CloudsWalker* walker, FuncCloudsWalkingCallback callback, void* data) { + while (cloudsWalkerPerformStep(walker)) + { + callback(walker); + } } diff --git a/src/rendering/clouds/clo_walking.h b/src/rendering/clouds/clo_walking.h index 28a77b7..49366da 100644 --- a/src/rendering/clouds/clo_walking.h +++ b/src/rendering/clouds/clo_walking.h @@ -26,9 +26,9 @@ typedef struct Vector3 end; double length; - int refined; + /*int refined; int subdivision_level; - double precision_asked; + double precision_asked;*/ void* data; } CloudWalkerStepInfo; @@ -65,12 +65,21 @@ CloudsWalker* cloudsCreateWalker(Renderer* renderer, CloudsLayerDefinition* laye */ 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. * * @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. diff --git a/src/testing/test_clouds.c b/src/testing/test_clouds.c index 68c6c05..add42e7 100644 --- a/src/testing/test_clouds.c +++ b/src/testing/test_clouds.c @@ -202,6 +202,7 @@ static double _getLayerDensitySinX(Renderer* renderer, CloudsLayerDefinition* la START_TEST(test_clouds_walking) { + /* Init */ CloudsLayerDefinition* layer; layer = cloudsGetLayerType().callback_create(); layer->lower_altitude = -1.0; @@ -214,7 +215,35 @@ START_TEST(test_clouds_walking) renderer->render_quality = 8; 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); rendererDelete(renderer);