bool plane_intersection_line(const struct plane *p, const struct vec3 *v1, const struct vec3 *v2, float *t) { float p1_dist, p2_dist, p1_abs_dist, dist2; bool p1_over, p2_over; p1_dist = vec3_plane_dist(v1, p); p2_dist = vec3_plane_dist(v2, p); if (close_float(p1_dist, 0.0f, EPSILON)) { if (close_float(p2_dist, 0.0f, EPSILON)) return false; *t = 0.0f; return true; } else if (close_float(p2_dist, 0.0f, EPSILON)) { *t = 1.0f; return true; } p1_over = (p1_dist > 0.0f); p2_over = (p2_dist > 0.0f); if (p1_over == p2_over) return false; p1_abs_dist = fabsf(p1_dist); dist2 = p1_abs_dist + fabsf(p2_dist); if (dist2 < EPSILON) return false; *t = p1_abs_dist / dist2; return true; }
bool plane_tri_inside(const struct plane *p, const struct vec3 *v1, const struct vec3 *v2, const struct vec3 *v3, float precision) { /* bit 1: part or all is behind the plane */ /* bit 2: part or all is in front of the plane */ int sides = 0; float d1 = vec3_plane_dist(v1, p); float d2 = vec3_plane_dist(v2, p); float d3 = vec3_plane_dist(v3, p); if (d1 >= precision) sides = 2; else if (d1 <= -precision) sides = 1; if (d2 >= precision) sides |= 2; else if (d2 <= -precision) sides |= 1; if (d3 >= precision) sides |= 2; else if (d3 <= -precision) sides |= 1; return sides; }
float bounds_min_dist(const struct bounds *b, const struct plane *p) { struct vec3 center; float vec_len = vec3or_offset_len(b, &p->dir) * 0.5f; float center_dist; bounds_get_center(¢er, b); center_dist = vec3_plane_dist(¢er, p); return p->dist + center_dist - vec_len; }
bool bounds_plane_test(const struct bounds *b, const struct plane *p) { struct vec3 vmin, vmax; int i; for (i = 0; i < 3; i++) { if (p->dir.ptr[i] >= 0.0f) { vmin.ptr[i] = b->min.ptr[i]; vmax.ptr[i] = b->max.ptr[i]; } else { vmin.ptr[i] = b->max.ptr[i]; vmax.ptr[i] = b->min.ptr[i]; } } if (vec3_plane_dist(&vmin, p) > 0.0f) return BOUNDS_OUTSIDE; if (vec3_plane_dist(&vmax, p) >= 0.0f) return BOUNDS_PARTIAL; return BOUNDS_INSIDE; }
int Polygon_RayIntersect(polygon_p p, float dir[3], float dot[3], float *t) { float tt, u, v, E1[3], E2[3], P[3], Q[3], T[3]; vertex_p vp; u = vec3_dot(p->plane, dir); if(fabs(u) < 0.001 /*|| vec3_plane_dist(p->plane, dot) < -0.001*/) // FIXME: magick { return 0; // plane is parallel to the ray - no intersection } *t = - vec3_plane_dist(p->plane, dot); *t /= u; vp = p->vertices; // current polygon pointer vec3_sub(T, dot, vp[0].position); vec3_sub(E2, vp[1].position, vp[0].position) for(uint16_t i = 0; i < p->vertex_count - 2; i++, vp++) { vec3_copy(E1, E2) // PREV vec3_sub(E2, vp[2].position, p->vertices[0].position) // NEXT vec3_cross(P, dir, E2) vec3_cross(Q, T, E1) tt = vec3_dot(P, E1); u = vec3_dot(P, T); u /= tt; v = vec3_dot(Q, dir); v /= tt; tt = 1.0 - u - v; if((u <= 1.0) && (u >= 0.0) && (v <= 1.0) && (v >= 0.0) && (tt <= 1.0) && (tt >= 0.0)) { return 1; } } return 0; }
int Polygon_SplitClassify(polygon_p p, float n[4]) { int i; int positive = 0; int negative = 0; float dist; vertex_p v; v = p->vertices; for (i=0;i<p->vertex_count;i++,v++) { dist = vec3_plane_dist(n, v->position); if (dist > SPLIT_EPSILON) { positive++; } else if (dist < -SPLIT_EPSILON) { negative++; } } if(positive > 0 && negative == 0) { return SPLIT_FRONT; } else if(positive == 0 && negative > 0) { return SPLIT_BACK; } else if (positive < 1 && negative < 1) { return SPLIT_IN_PLANE; } return SPLIT_IN_BOTH; }
/* * animated textures coordinates splits too! */ void Polygon_Split(polygon_p src, float n[4], polygon_p front, polygon_p back) { float t, tmp, dir[3]; vertex_t *curr_v, *prev_v, tv; float dist[2]; vec4_copy(front->plane, src->plane); front->anim_id = src->anim_id; front->frame_offset = src->frame_offset; front->double_side = src->double_side; front->texture_index = src->texture_index; front->transparency = src->transparency; vec4_copy(back->plane, src->plane); back->anim_id = src->anim_id; back->frame_offset = src->frame_offset; back->double_side = src->double_side; back->texture_index = src->texture_index; back->transparency = src->transparency; curr_v = src->vertices; prev_v = src->vertices + src->vertex_count - 1; dist[0] = vec3_plane_dist(n, prev_v->position); for(uint16_t i = 0; i < src->vertex_count; i++) { dist[1] = vec3_plane_dist(n, curr_v->position); if(dist[1] > SPLIT_EPSILON) { if(dist[0] < -SPLIT_EPSILON) { vec3_sub(dir, curr_v->position, prev_v->position); vec3_ray_plane_intersect(prev_v->position, dir, n, tv.position, t); tv.normal[0] = prev_v->normal[0] + t * (curr_v->normal[0] - prev_v->normal[0]); tv.normal[1] = prev_v->normal[1] + t * (curr_v->normal[1] - prev_v->normal[1]); tv.normal[2] = prev_v->normal[2] + t * (curr_v->normal[2] - prev_v->normal[2]); vec3_norm(tv.normal, tmp); tv.color[0] = prev_v->color[0] + t * (curr_v->color[0] - prev_v->color[0]); tv.color[1] = prev_v->color[1] + t * (curr_v->color[1] - prev_v->color[1]); tv.color[2] = prev_v->color[2] + t * (curr_v->color[2] - prev_v->color[2]); tv.color[3] = prev_v->color[3] + t * (curr_v->color[3] - prev_v->color[3]); tv.tex_coord[0] = prev_v->tex_coord[0] + t * (curr_v->tex_coord[0] - prev_v->tex_coord[0]); tv.tex_coord[1] = prev_v->tex_coord[1] + t * (curr_v->tex_coord[1] - prev_v->tex_coord[1]); front->vertices[front->vertex_count++] = tv; back->vertices[back->vertex_count++] = tv; } front->vertices[front->vertex_count++] = *curr_v; } else if(dist[1] < -SPLIT_EPSILON) { if(dist[0] > SPLIT_EPSILON) { vec3_sub(dir, curr_v->position, prev_v->position); vec3_ray_plane_intersect(prev_v->position, dir, n, tv.position, t); tv.normal[0] = prev_v->normal[0] + t * (curr_v->normal[0] - prev_v->normal[0]); tv.normal[1] = prev_v->normal[1] + t * (curr_v->normal[1] - prev_v->normal[1]); tv.normal[2] = prev_v->normal[2] + t * (curr_v->normal[2] - prev_v->normal[2]); vec3_norm(tv.normal, tmp); tv.color[0] = prev_v->color[0] + t * (curr_v->color[0] - prev_v->color[0]); tv.color[1] = prev_v->color[1] + t * (curr_v->color[1] - prev_v->color[1]); tv.color[2] = prev_v->color[2] + t * (curr_v->color[2] - prev_v->color[2]); tv.color[3] = prev_v->color[3] + t * (curr_v->color[3] - prev_v->color[3]); tv.tex_coord[0] = prev_v->tex_coord[0] + t * (curr_v->tex_coord[0] - prev_v->tex_coord[0]); tv.tex_coord[1] = prev_v->tex_coord[1] + t * (curr_v->tex_coord[1] - prev_v->tex_coord[1]); front->vertices[front->vertex_count++] = tv; back->vertices[back->vertex_count++] = tv; } back->vertices[back->vertex_count++] = *curr_v; } else { front->vertices[front->vertex_count++] = *curr_v; back->vertices[back->vertex_count++] = *curr_v; } prev_v = curr_v; curr_v ++; dist[0] = dist[1]; } }
int Polygon_IntersectPolygon(polygon_p p1, polygon_p p2) { float dist[3], dir[3], t, *result_buf, *result_v; vertex_p prev_v, curr_v; size_t buf_size; char cnt = 0; if(SPLIT_IN_BOTH != Polygon_SplitClassify(p1, p2->plane) || (SPLIT_IN_BOTH != Polygon_SplitClassify(p2, p1->plane))) { return 0; // quick check } buf_size = (p1->vertex_count + p2->vertex_count) * 3 * sizeof(float); result_buf = (float*)Sys_GetTempMem(buf_size); result_v = result_buf; /* * intersection of polygon p1 and plane p2 */ prev_v = p1->vertices + p1->vertex_count - 1; curr_v = p1->vertices; dist[0] = vec3_plane_dist(p2->plane, prev_v->position); for(uint16_t i = 0; i < p1->vertex_count; i++) { dist[1] = vec3_plane_dist(p2->plane, curr_v->position); if(dist[1] > SPLIT_EPSILON) { if(dist[0] < -SPLIT_EPSILON) { vec3_sub(dir, curr_v->position, prev_v->position); vec3_ray_plane_intersect(prev_v->position, dir, p2->plane, result_v, t); result_v += 3; cnt++; } } else if(dist[1] < -SPLIT_EPSILON) { if(dist[0] > SPLIT_EPSILON) { vec3_sub(dir, curr_v->position, prev_v->position); vec3_ray_plane_intersect(prev_v->position, dir, p2->plane, result_v, t); result_v += 3; cnt++; } } else { vec3_copy(result_v, curr_v->position); result_v += 3; cnt++; } if(cnt >= 2) { break; } dist[0] = dist[1]; prev_v = curr_v; curr_v ++; } /* * splitting p2 by p1 split plane */ prev_v = p2->vertices + p2->vertex_count - 1; curr_v = p2->vertices; dist[0] = vec3_plane_dist(p1->plane, prev_v->position); for(uint16_t i = 0; i < p2->vertex_count; i++) { dist[1] = vec3_plane_dist(p1->plane, curr_v->position); if(dist[1] > SPLIT_EPSILON) { if(dist[0] < -SPLIT_EPSILON) { vec3_sub(dir, curr_v->position, prev_v->position); vec3_ray_plane_intersect(prev_v->position, dir, p1->plane, result_v, t); result_v += 3; cnt++; } } else if(dist[1] < -SPLIT_EPSILON) { if(dist[0] > SPLIT_EPSILON) { vec3_sub(dir, curr_v->position, prev_v->position); vec3_ray_plane_intersect(prev_v->position, dir, p1->plane, result_v, t); result_v += 3; cnt++; } } else { vec3_copy(result_v, curr_v->position); result_v += 3; cnt++; } if(cnt >= 4) { break; } dist[0] = dist[1]; prev_v = curr_v; curr_v ++; } vec3_cross(dir, p1->plane, p2->plane); // vector of two planes intersection line t = ABS(dir[0]); dist[0] = ABS(dir[1]); dist[1] = ABS(dir[2]); int pn = PLANE_X; if(t < dist[0]) { t = dist[0]; pn = PLANE_Y; } if(t < dist[1]) { pn = PLANE_Z; } switch(pn) { case PLANE_X: dist[0] = (result_buf[3+0] - result_buf[0]) / dir[0]; dist[1] = (result_buf[6+0] - result_buf[0]) / dir[0]; dist[2] = (result_buf[9+0] - result_buf[0]) / dir[0]; break; case PLANE_Y: dist[0] = (result_buf[3+1] - result_buf[1]) / dir[1]; dist[1] = (result_buf[6+1] - result_buf[1]) / dir[1]; dist[2] = (result_buf[9+1] - result_buf[1]) / dir[1]; break; case PLANE_Z: dist[0] = (result_buf[3+2] - result_buf[2]) / dir[2]; dist[1] = (result_buf[6+2] - result_buf[2]) / dir[2]; dist[2] = (result_buf[9+2] - result_buf[2]) / dir[2]; break; }; Sys_ReturnTempMem(buf_size); if(dist[0] > 0) { return !((dist[1] < 0.0 && dist[2] < 0.0) || (dist[1] > dist[0] && dist[2] > dist[0])); } return !((dist[1] < dist[0] && dist[2] < dist[0]) || (dist[1] > 0.0 && dist[2] > 0.0)); }
void CDynamicBSP::AddPolygon(struct bsp_node_s *root, struct polygon_s *p) { if(m_realloc_state) { return; } if(m_tree_allocated + 1024 > m_tree_buffer_size) { m_realloc_state = NEED_REALLOC_TREE_BUFF; return; } if(m_temp_allocated + 1024 > m_temp_buffer_size) { m_realloc_state = NEED_REALLOC_TEMP_BUFF; return; } if(root->polygons_front == NULL) { // we though root->front == NULL and root->back == NULL vec4_copy(root->plane, p->plane); p->next = NULL; this->AddBSPPolygon(root, p); return; } uint16_t positive = 0; uint16_t negative = 0; uint16_t in_plane = 0; float dist; vertex_p v = p->vertices; for(uint16_t i = 0; i < p->vertex_count; i++, v++) { dist = vec3_plane_dist(root->plane, v->position); if (dist > SPLIT_EPSILON) { positive++; } else if (dist < -SPLIT_EPSILON) { negative++; } else { in_plane++; } } if ((positive > 0) && (negative == 0)) // SPLIT_FRONT { if (root->front == NULL) { root->front = this->CreateBSPNode(); } this->AddPolygon(root->front, p); } else if ((positive == 0) && (negative > 0)) // SPLIT_BACK { if (root->back == NULL) { root->back = this->CreateBSPNode(); } this->AddPolygon(root->back, p); } else if ((positive == 0) && (negative == 0)) // SPLIT_IN_PLANE { this->AddBSPPolygon(root, p); } else // SPLIT_IN_BOTH { polygon_p front, back; front = this->CreatePolygon(p->vertex_count + 2); front->vertex_count = 0; back = this->CreatePolygon(p->vertex_count + 2); back->vertex_count = 0; Polygon_Split(p, root->plane, front, back); if(root->front == NULL) { root->front = this->CreateBSPNode(); } this->AddPolygon(root->front, front); if(root->back == NULL) { root->back = this->CreateBSPNode(); } this->AddPolygon(root->back, back); } }