/* COLLISION_MODELS.C */ /* ---------- headers */ #include "cseries.h" #include "collisions.h" #include "collision_bsp.h" #include "collision_bsp_definitions.h" #include "collision_model_definitions.h" #include "collision_models.h" #include "collision_usage.h" #include "objects/object_types.h" #include "objects/objects.h" #include "tag_files/tag_groups.h" /* ---------- constants */ /* ---------- macros */ /* ---------- structures */ /* ---------- prototypes */ long bsp3d_test_point(const struct bsp3d *bsp, long node_index, const real_point3d *point); boolean collision_bsp_test_vector( unsigned long flags, const struct collision_bsp *bsp, short breakable_surface_count, const byte *breakable_surface_flags, const real_point3d *point, const real_vector3d *vector, real maximum_t, struct collision_bsp_test_vector_result *result); boolean collision_bsp_test_pill( const struct collision_bsp *bsp, const real_point3d *point, const real_vector3d *vector, real radius, real maximum_t, struct collision_bsp_test_pill_result *result); void collision_bsp_get_features_in_sphere( const struct collision_bsp *bsp, const struct collision_bsp_test_sphere_result *result, const real_matrix4x3 *matrix, real height, real width, long object_index, struct collision_feature_list *features); void render_debug_collision_bsp(struct collision_bsp *bsp, const real_matrix4x3 *matrix); /* ---------- globals */ /* ---------- public code */ boolean collision_model_instance_new( struct collision_model_instance *instance, long object_index) { boolean result = FALSE; struct object_datum *object = object_get(object_index); struct object_definition *object_definition = object_definition_get(object->definition_index); if (object_definition->object.collision_model.index != NONE) { instance->object_index = object_index; instance->model = collision_model_definition_get(object_definition->object.collision_model.index); instance->region_permutation_indices = object->object.region_permutations; instance->matrices = object_get_node_matrices(object_index); result = TRUE; } return result; } boolean collision_model_test_sphere( struct collision_model_instance const *instance, real_point3d const *center, real radius) { const struct collision_node *collision_node; struct collision_bsp *collision_bsp; short node_index; short perm; real_point3d transformed_center; real_matrix4x3 inverted_matrix; for (node_index = 0; node_index < instance->model->nodes.count; ++node_index) { collision_node = TAG_BLOCK_GET_ELEMENT(&instance->model->nodes, node_index, struct collision_node); if (collision_node->region_index != NONE) { perm = instance->region_permutation_indices[collision_node->region_index]; if (perm != NONE && collision_node->bsps.count > 0) { perm = PIN(perm, 0, collision_node->bsps.count - 1); collision_bsp = TAG_BLOCK_GET_ELEMENT(&collision_node->bsps, perm, struct collision_bsp); if (collision_bsp->bsp3d.nodes.count > 0) { matrix4x3_inverse(&instance->matrices[node_index], &inverted_matrix); matrix4x3_transform_point(&inverted_matrix, center, &transformed_center); } } } } return FALSE; } boolean collision_model_test_point( struct collision_model_instance const *instance, real_point3d const *point) { const struct collision_node *collision_node; struct collision_bsp *collision_bsp; short i; short perm; real_point3d transformed_point; for (i = 0; i < instance->model->nodes.count; i++) { collision_node = TAG_BLOCK_GET_ELEMENT(&instance->model->nodes, i, struct collision_node); if (collision_node->region_index != NONE) { perm = instance->region_permutation_indices[collision_node->region_index]; if (perm != NONE && collision_node->bsps.count > 0) { perm = PIN(perm, 0, collision_node->bsps.count - 1); collision_bsp = TAG_BLOCK_GET_ELEMENT(&collision_node->bsps, perm, struct collision_bsp); if (collision_bsp->bsp3d.nodes.count > 0) { matrix4x3_inverse_transform_point(&instance->matrices[i], point, &transformed_point); if (bsp3d_test_point(&collision_bsp->bsp3d, 0, &transformed_point) == NONE) { return TRUE; } } } } } return FALSE; } boolean collision_model_test_vector( struct collision_model_instance const *instance, unsigned long flags, real_point3d const *point, real_vector3d const *vector, struct collision_model_test_vector_result *result) { short node_index; boolean return_value = FALSE; static __int64 collision_model_test_vector_time; collision_log_usage(3); collision_log_start_time(&collision_model_test_vector_time); result->bsp_result.t = FLT_MAX; for (node_index = 0; node_index < instance->model->nodes.count; ++node_index) { struct collision_node const *collision_node = TAG_BLOCK_GET_ELEMENT(&instance->model->nodes, node_index, struct collision_node); if (collision_node->region_index != NONE) { short perm = instance->region_permutation_indices[collision_node->region_index]; if (perm != NONE && collision_node->bsps.count > 0) { struct collision_bsp *collision_bsp; perm = PIN(perm, 0, collision_node->bsps.count - 1); collision_bsp = TAG_BLOCK_GET_ELEMENT(&collision_node->bsps, perm, struct collision_bsp); if (collision_bsp->bsp3d.nodes.count > 0) { real_matrix4x3 inverted_matrix; real_point3d transformed_point; real_vector3d transformed_vector; matrix4x3_inverse(&instance->matrices[node_index], &inverted_matrix); matrix4x3_transform_point(&inverted_matrix, point, &transformed_point); matrix4x3_transform_vector(&inverted_matrix, vector, &transformed_vector); if (collision_bsp_test_vector(flags, collision_bsp, 0, NULL, &transformed_point, &transformed_vector, result->bsp_result.t, &result->bsp_result)) { result->node_index = node_index; result->region_index = collision_node->region_index; result->bsp_index = perm; return_value = TRUE; } } } } } collision_log_end_time(3, collision_model_test_vector_time); return return_value; } boolean collision_model_test_pill( struct collision_model_instance const *instance, real_point3d const *point, real_vector3d const *vector, real radius, struct collision_model_test_pill_result *result) { const struct collision_node *collision_node; struct collision_bsp *collision_bsp; short i; short perm; real_point3d transformed_point; real_matrix4x3 inverted_matrix; real_vector3d transformed_vector; boolean return_val; real scaled_radius; result->bsp_result.t = FLT_MAX; return_val = FALSE; for (i = 0; i < instance->model->nodes.count; i++) { collision_node = TAG_BLOCK_GET_ELEMENT(&instance->model->nodes, i, struct collision_node); if (collision_node->region_index != NONE) { perm = instance->region_permutation_indices[collision_node->region_index]; if (perm != NONE && collision_node->bsps.count > 0) { perm = PIN(perm, 0, collision_node->bsps.count - 1); collision_bsp = TAG_BLOCK_GET_ELEMENT(&collision_node->bsps, perm, struct collision_bsp); if (collision_bsp->bsp3d.nodes.count > 0) { matrix4x3_inverse(&instance->matrices[i], &inverted_matrix); matrix4x3_transform_point(&inverted_matrix, point, &transformed_point); matrix4x3_transform_vector(&inverted_matrix, vector, &transformed_vector); scaled_radius = inverted_matrix.scale * radius; if (collision_bsp_test_pill( collision_bsp, &transformed_point, &transformed_vector, scaled_radius, result->bsp_result.t, &result->bsp_result)) { result->node_index = i; result->region_index = collision_node->region_index; result->bsp_index = perm; return_val = TRUE; } } } } } return return_val; } boolean collision_model_get_features_in_sphere( const struct collision_model_instance *instance, const real_point3d *center, real radius, real height, real width, struct collision_feature_list *features) { const struct collision_node *collision_node; struct collision_bsp *collision_bsp; short i; short perm; real_point3d transformed_center; real_matrix4x3 inverted_matrix; boolean return_val; struct collision_bsp_test_sphere_result result; real scaled_radius; const real_matrix4x3 *matrix; return_val = FALSE; for (i = 0; i < instance->model->nodes.count; i++) { collision_node = TAG_BLOCK_GET_ELEMENT(&instance->model->nodes, i, struct collision_node); if (collision_node->region_index != NONE) { perm = instance->region_permutation_indices[collision_node->region_index]; if (perm != NONE && collision_node->bsps.count > 0) { perm = PIN(perm, 0, collision_node->bsps.count - 1); collision_bsp = TAG_BLOCK_GET_ELEMENT(&collision_node->bsps, perm, struct collision_bsp); if (collision_bsp->bsp3d.nodes.count > 0) { matrix = &instance->matrices[i]; matrix4x3_inverse(matrix, &inverted_matrix); matrix4x3_transform_point(&inverted_matrix, center, &transformed_center); scaled_radius = inverted_matrix.scale * radius; if (collision_bsp_test_sphere( collision_bsp, 0, 0, &transformed_center, scaled_radius, &result)) { collision_bsp_get_features_in_sphere( collision_bsp, &result, matrix, height, width, instance->object_index, features); return_val = TRUE; } } } } } return return_val; } void render_debug_collision_model( struct collision_model_instance const *instance) { const struct collision_node *collision_node; struct collision_bsp *collision_bsp; short i; short perm; for (i = 0; i < instance->model->nodes.count; i++) { collision_node = TAG_BLOCK_GET_ELEMENT(&instance->model->nodes, i, struct collision_node); if (collision_node->region_index != NONE) { perm = instance->region_permutation_indices[collision_node->region_index]; if (perm != NONE && collision_node->bsps.count > 0) { perm = PIN(perm, 0, collision_node->bsps.count - 1); collision_bsp = TAG_BLOCK_GET_ELEMENT(&collision_node->bsps, perm, struct collision_bsp); if (collision_bsp->surfaces.count > 0 && collision_bsp->edges.count > 0 && collision_bsp->vertices.count > 0) { render_debug_collision_bsp(collision_bsp, &instance->matrices[i]); } } } } } /* ---------- private code */