+ goals->colors[i] = hexstr(color);
+ goals->cue_states[i] = CUE_STATE_VIRGIN;
+ goals->visible[i] = true;
+ }
+
+ goals->lt = lt;
+ goals->angle = 0.0f;
+
+ return goals;
+}
+
+Goals *create_goals_from_point_layer(const PointLayer *point_layer)
+{
+ trace_assert(point_layer);
+
+ Lt *lt = create_lt();
+
+ Goals *const goals = PUSH_LT(lt, nth_calloc(1, sizeof(Goals)), free);
+ if (goals == NULL) {
+ RETURN_LT(lt, NULL);
+ }
+
+ goals->count = point_layer_count(point_layer);
+
+ goals->ids = PUSH_LT(
+ lt,
+ nth_calloc(1, sizeof(char*) * goals->count),
+ free);
+ if (goals->ids == NULL) {
+ RETURN_LT(lt, NULL);
+ }
+ for (size_t i = 0; i < goals->count; ++i) {
+ goals->ids[i] = PUSH_LT(lt, nth_calloc(1, sizeof(char) * GOAL_MAX_ID_SIZE), free);
+ if (goals->ids[i] == NULL) {
+ RETURN_LT(lt, NULL);
+ }
+ }
+
+ goals->positions = PUSH_LT(lt, nth_calloc(1, sizeof(Point) * goals->count), free);
+ if (goals->positions == NULL) {
+ RETURN_LT(lt, NULL);
+ }
+
+ goals->colors = PUSH_LT(lt, nth_calloc(1, sizeof(Color) * goals->count), free);
+ if (goals->colors == NULL) {
+ RETURN_LT(lt, NULL);
+ }
+
+ goals->cue_states = PUSH_LT(lt, nth_calloc(1, sizeof(int) * goals->count), free);
+ if (goals->cue_states == NULL) {
+ RETURN_LT(lt, NULL);
+ }
+
+ goals->visible = PUSH_LT(lt, nth_calloc(1, sizeof(bool) * goals->count), free);
+ if (goals->visible == NULL) {
+ RETURN_LT(lt, NULL);
+ }
+
+ const Point *positions = point_layer_positions(point_layer);
+ const Color *colors = point_layer_colors(point_layer);
+ const char *ids = point_layer_ids(point_layer);
+
+ // TODO(#835): we could use memcpy in create_goals_from_point_layer
+ for (size_t i = 0; i < goals->count; ++i) {
+ goals->positions[i] = positions[i];
+ goals->colors[i] = colors[i];
+ memcpy(goals->ids[i], ids + ID_MAX_SIZE * i, ID_MAX_SIZE);