void _serialize(MMLObject* mml, DArray* out, NodeIdx node, uint padding) { assert(mml); assert(out); MMLNode* node_ptr = mml_get_nodeptr(mml, node); uint i = padding; while(i--) { darray_append(out, " "); } const char* name = mml_get_str(mml, node_ptr->name_start); const char* value = mml_get_str(mml, node_ptr->value_start); darray_append_multi(out, "( ", 2); mml_insert_escapes(name, out); darray_append(out, " "); mml_insert_escapes(value, out); if(node_ptr->first_child_idx == 0) { // node has no children, print it on a single line darray_append_multi(out, " )\n", 3); return; } else { // node has children, recurse darray_append(out, "\n"); NodeIdx child = node_ptr->first_child_idx; while(child) { _serialize(mml, out, child, padding + 4); child = mml_get_next(mml, child); } i = padding; while(i--) { darray_append(out, " "); } darray_append_multi(out, ")\n", 2); } }
DArray _gen_navpoints(DArray geometry, DArray platforms) { DArray points = darray_create(sizeof(Vector2), 0); darray_append_multi(&points, platforms.data, platforms.size); uint fail_count = 0; do { Vector2 navpoint = vec2(rand_float_range(0.0f, SCREEN_WIDTH), rand_float_range(0.0f, SCREEN_HEIGHT)); float wdist = ai_wall_distance(navpoint, geometry); float pdist = _point_distance(navpoint, points); if(wdist >= min_wall_distance && pdist >= min_point_distance) { darray_append(&points, (void*)&navpoint); fail_count = 0; } else { fail_count++; } } while(fail_count < 1200); return points; }
NavMesh ai_precalc_navmesh(DArray geometry, DArray platforms, float width, float height) { NavMesh res; ai_precalc_bounds(width, height); DArray navpoints = _gen_navpoints(geometry, platforms); DArray edges = _gen_edges(navpoints, geometry); Vector2* navpoints_v = DARRAY_DATA_PTR(navpoints, Vector2); Edge* edges_e = DARRAY_DATA_PTR(edges, Edge); uint n = navpoints.size; res.n_nodes = n; res.navpoints = MEM_ALLOC(sizeof(Vector2) * n); res.neighbour_count = MEM_ALLOC(sizeof(uint) * n); res.neighbours_start = MEM_ALLOC(sizeof(uint) * n); float* adjacency = MEM_ALLOC(sizeof(float) * n*n); res.distance = MEM_ALLOC(sizeof(float) * n*n); res.radius = MEM_ALLOC(sizeof(float) * n); res.nn_grid_count = MEM_ALLOC(sizeof(uint) * nn_grid_cells); res.nn_grid_start = MEM_ALLOC(sizeof(uint) * nn_grid_cells); memset(res.neighbour_count, 0, sizeof(uint) * n); memset(adjacency, 0, sizeof(float) * n*n); memset(res.distance, 0, sizeof(float) * n*n); memset(res.nn_grid_count, 0, sizeof(uint) * nn_grid_cells); memset(res.nn_grid_start, 0, sizeof(uint) * nn_grid_cells); for(uint i = 0; i < navpoints.size; ++i) { res.navpoints[i] = navpoints_v[i]; res.radius[i] = ai_wall_distance(navpoints_v[i], geometry); } for(uint i = 0; i < edges.size; ++i) { float dist = vec2_length(vec2_sub( navpoints_v[edges_e[i].v1], navpoints_v[edges_e[i].v2])); adjacency[IDX_2D(edges_e[i].v1, edges_e[i].v2, n)] = dist; adjacency[IDX_2D(edges_e[i].v2, edges_e[i].v1, n)] = dist; res.neighbour_count[edges_e[i].v1]++; res.neighbour_count[edges_e[i].v2]++; } // Pracalc node neighbour lists uint total_neighbours = res.neighbour_count[0]; res.neighbours_start[0] = 0; for(uint i = 1; i < n; ++i) { res.neighbours_start[i] = res.neighbours_start[i-1] + res.neighbour_count[i-1]; total_neighbours += res.neighbour_count[i]; } res.neighbours = MEM_ALLOC(sizeof(uint) * total_neighbours); for(uint i = 0; i < n; ++i) { uint idx = res.neighbours_start[i]; for(uint j = 0; j < n; ++j) { if(adjacency[IDX_2D(i, j, n)] > 0.0f) res.neighbours[idx++] = j; } assert(idx == res.neighbours_start[i] + res.neighbour_count[i]); } memcpy(res.distance, adjacency, sizeof(float) * n*n); // Change zero distances to infinities for(uint i = 0; i < n*n; ++i) if(res.distance[i] == 0.0f) res.distance[i] = 10000000.0f; // Floyd-Warshall for(uint i = 0; i < n; ++i) for(uint j = 0; j < n; ++j) for(uint k = 0; k < n; ++k) res.distance[IDX_2D(j, k, n)] = MIN(res.distance[IDX_2D(j, k, n)], res.distance[IDX_2D(j, i, n)]+res.distance[IDX_2D(i, k, n)]); // Precalc nearest-navpoint grid DArray grid_cell; DArray nn_grid; res.nn_grid_start[0] = 0; nn_grid = darray_create(sizeof(uint), 0); for(uint i = 0; i < nn_grid_cells; ++i) { grid_cell = darray_create(sizeof(uint), 0); for(uint j = 0; j < nn_samples; ++j) { Vector2 p = _rand_point_in_nn_grid_cell(i); uint nearest_navpoint = _nearest_navpoint(p, geometry, navpoints); if(nearest_navpoint >= n) // Point was inside wall, skip continue; bool unique = true; uint* existing_navpoints = DARRAY_DATA_PTR(grid_cell, uint); for(uint k = 0; k < grid_cell.size; ++k) if(existing_navpoints[k] == nearest_navpoint) unique = false; if(unique) darray_append(&grid_cell, &nearest_navpoint); } res.nn_grid_count[i] = grid_cell.size; if(i > 0) res.nn_grid_start[i] = res.nn_grid_start[i-1] + res.nn_grid_count[i-1]; uint* cell_navpoints = DARRAY_DATA_PTR(grid_cell, uint); darray_append_multi(&nn_grid, cell_navpoints, grid_cell.size); darray_free(&grid_cell); } // Hack, works properly as long as darray_free only does // MEM_FREE(darray.data); res.nn_grid = (uint*)nn_grid.data; darray_free(&navpoints); darray_free(&edges); MEM_FREE(adjacency); _precalc_vis(geometry, &res); return res; }