void TextureProjection::emitTextureCoordinates (std::size_t width, std::size_t height, Winding& w, const Vector3& normal, const Matrix4& localToWorld) { if (w.size() < 3) { return; } Matrix4 local2tex = m_texdef.getTransform((float) width, (float) height); { Matrix4 xyz2st; // we don't care if it's not normalised... basisForNormal(matrix4_transformed_direction(localToWorld, normal), xyz2st); matrix4_multiply_by_matrix4(local2tex, xyz2st); } Vector3 tangent(local2tex.getTransposed().x().getVector3().getNormalised()); Vector3 bitangent(local2tex.getTransposed().y().getVector3().getNormalised()); matrix4_multiply_by_matrix4(local2tex, localToWorld); for (Winding::iterator i = w.begin(); i != w.end(); ++i) { Vector3 texcoord = matrix4_transformed_point(local2tex, (*i).vertex); (*i).texcoord[0] = texcoord[0]; (*i).texcoord[1] = texcoord[1]; (*i).tangent = tangent; (*i).bitangent = bitangent; } }
static Winding* NewWindingFromPlane(const brushhull_t* const hull, const int planenum) { Winding* winding; Winding* front; Winding* back; bface_t* face; plane_t* plane; plane = &g_mapplanes[planenum]; winding = new Winding(plane->normal, plane->dist); for (face = hull->faces; face; face = face->next) { plane = &g_mapplanes[face->planenum]; winding->Clip(plane->normal, plane->dist, &front, &back); delete winding; if (front) { delete front; } if (back) { winding = back; } else { Developer(DEVELOPER_LEVEL_ERROR, "NewFaceFromPlane returning NULL"); return NULL; } } return winding; }
static void WritePortalFile_r(const node_t* const node) { int i; portal_t* p; Winding* w; dplane_t plane2; if (!node->contents) { WritePortalFile_r(node->children[0]); WritePortalFile_r(node->children[1]); return; } if (node->contents == CONTENTS_SOLID) { return; } for (p = node->portals; p;) { w = p->winding; if (w && p->nodes[0] == node) { if (p->nodes[0]->contents == p->nodes[1]->contents) { // write out to the file // sometimes planes get turned around when they are very near // the changeover point between different axis. interpret the // plane the same way vis will, and flip the side orders if needed w->getPlane(plane2); if (DotProduct(p->plane.normal, plane2.normal) < 1.0 - ON_EPSILON) { // backwards... fprintf(pf, "%u %i %i ", w->m_NumPoints, p->nodes[1]->visleafnum, p->nodes[0]->visleafnum); } else { fprintf(pf, "%u %i %i ", w->m_NumPoints, p->nodes[0]->visleafnum, p->nodes[1]->visleafnum); } for (i = 0; i < w->m_NumPoints; i++) { fprintf(pf, "(%f %f %f) ", w->m_Points[i][0], w->m_Points[i][1], w->m_Points[i][2]); } fprintf(pf, "\n"); } } if (p->nodes[0] == node) { p = p->next[0]; } else { p = p->next[1]; } } }
brushsplit_t Winding_ClassifyPlane(const Winding& winding, const Plane3& plane) { brushsplit_t split; for(Winding::const_iterator i = winding.begin(); i != winding.end(); ++i) { ++split.counts[Winding_ClassifyDistance(plane3_distance_to_point(plane, (*i).vertex), ON_EPSILON)]; } return split; }
/// \brief Returns true if /// !flipped && winding is completely BACK or ON /// or flipped && winding is completely FRONT or ON bool Winding_TestPlane(const Winding& winding, const Plane3& plane, bool flipped) { const int test = (flipped) ? ePlaneBack : ePlaneFront; for(Winding::const_iterator i = winding.begin(); i != winding.end(); ++i) { if(test == Winding_ClassifyDistance(plane3_distance_to_point(plane, (*i).vertex), ON_EPSILON)) { return false; } } return true; }
void TextureProjection::fitTexture (std::size_t width, std::size_t height, const Vector3& normal, const Winding& w, float s_repeat, float t_repeat) { if (w.size() < 3) { return; } Matrix4 st2tex = m_texdef.getTransform((float) width, (float) height); // the current texture transform Matrix4 local2tex = st2tex; { Matrix4 xyz2st; basisForNormal(normal, xyz2st); matrix4_multiply_by_matrix4(local2tex, xyz2st); } // the bounds of the current texture transform AABB bounds; for (Winding::const_iterator i = w.begin(); i != w.end(); ++i) { Vector3 texcoord = matrix4_transformed_point(local2tex, (*i).vertex); aabb_extend_by_point_safe(bounds, texcoord); } bounds.origin.z() = 0; bounds.extents.z() = 1; // the bounds of a perfectly fitted texture transform AABB perfect(Vector3(s_repeat * 0.5, t_repeat * 0.5, 0), Vector3(s_repeat * 0.5, t_repeat * 0.5, 1)); // the difference between the current texture transform and the perfectly fitted transform Matrix4 matrix(Matrix4::getTranslation(bounds.origin - perfect.origin)); matrix4_pivoted_scale_by_vec3(matrix, bounds.extents / perfect.extents, perfect.origin); matrix4_affine_invert(matrix); // apply the difference to the current texture transform matrix4_premultiply_by_matrix4(st2tex, matrix); setTransform((float) width, (float) height, st2tex); m_texdef.normalise((float) width, (float) height); }
// AJM: MVD // ===================================================================================== // ClipWindingsToBounds // clips all the windings with all the planes (including original face) and outputs // what's left int "out" // ===================================================================================== static void ClipWindingsToBounds(winding_t *windings, int numwindings, plane_t *bounds, int numbounds, plane_t &original_plane, winding_t **out, int &num_out) { hlassert(windings); hlassert(bounds); winding_t out_windings[MAX_PORTALS_ON_LEAF]; num_out = 0; int h, i; *out = NULL; Winding wind; for(h = 0; h < numwindings; h++) { // For each winding... // Create a winding with CWinding wind.initFromPoints(windings[h].points, windings[h].numpoints); // Clip winding to original plane wind.Chop(original_plane.normal, original_plane.dist); for(i = 0; i < numbounds, wind.Valid(); i++) { // For each bound... // Chop the winding to the bounds wind.Chop(bounds[i].normal, bounds[i].dist); } if(wind.Valid()) { // We have a valid winding, copy to array wind.CopyPoints(&out_windings[num_out].points[0], out_windings[num_out].numpoints); num_out++; } } if(!num_out) // Everything was clipped away return; // Otherwise, create out *out = new winding_t[num_out]; memcpy(*out, out_windings, num_out * sizeof(winding_t)); }
bool Winding::planesConcave(const Winding& w1, const Winding& w2, const Plane3& plane1, const Plane3& plane2) { return !w1.testPlane(plane2, false) || !w2.testPlane(plane1, false); }
// ===================================================================================== // GetAlternateOrigin // ===================================================================================== void GetAlternateOrigin (const vec3_t pos, const vec3_t normal, const patch_t *patch, vec3_t &origin) { const dplane_t *faceplane; const vec_t *faceplaneoffset; const vec_t *facenormal; dplane_t clipplane; Winding w; faceplane = getPlaneFromFaceNumber (patch->faceNumber); faceplaneoffset = g_face_offset[patch->faceNumber]; facenormal = faceplane->normal; VectorCopy (normal, clipplane.normal); clipplane.dist = DotProduct (pos, clipplane.normal); w = *patch->winding; if (w.WindingOnPlaneSide (clipplane.normal, clipplane.dist) != SIDE_CROSS) { VectorCopy (patch->origin, origin); } else { w.Clip (clipplane, false); if (w.m_NumPoints == 0) { VectorCopy (patch->origin, origin); } else { vec3_t center; bool found; vec3_t bestpoint; vec_t bestdist = -1.0; vec3_t point; vec_t dist; vec3_t v; w.getCenter (center); found = false; VectorMA (center, PATCH_HUNT_OFFSET, facenormal, point); if (HuntForWorld (point, faceplaneoffset, faceplane, 2, 1.0, PATCH_HUNT_OFFSET)) { VectorSubtract (point, center, v); dist = VectorLength (v); if (!found || dist < bestdist) { found = true; VectorCopy (point, bestpoint); bestdist = dist; } } if (!found) { for (int i = 0; i < w.m_NumPoints; i++) { const vec_t *p1; const vec_t *p2; p1 = w.m_Points[i]; p2 = w.m_Points[(i + 1) % w.m_NumPoints]; VectorAdd (p1, p2, point); VectorAdd (point, center, point); VectorScale (point, 1.0/3.0, point); VectorMA (point, PATCH_HUNT_OFFSET, facenormal, point); if (HuntForWorld (point, faceplaneoffset, faceplane, 1, 0.0, PATCH_HUNT_OFFSET)) { VectorSubtract (point, center, v); dist = VectorLength (v); if (!found || dist < bestdist) { found = true; VectorCopy (point, bestpoint); bestdist = dist; } } } } if (found) { VectorCopy (bestpoint, origin); } else { VectorCopy (patch->origin, origin); } } } }
// ===================================================================================== // snap_to_winding_noedge // first snaps the point into the winding // then moves the point towards the inside for at most certain distance until: // either 1) the point is not close to any of the edges // or 2) the point can not be moved any more // returns the maximal distance that the point can be kept away from all the edges // in most of the cases, the maximal distance = width; in other cases, the maximal distance < width // ===================================================================================== vec_t snap_to_winding_noedge(const Winding& w, const dplane_t& plane, vec_t* const point, vec_t width, vec_t maxmove) { int pass; int numplanes; dplane_t *planes; int x; vec3_t v; vec_t newwidth; vec_t bestwidth; vec3_t bestpoint; snap_to_winding (w, plane, point); planes = (dplane_t *)malloc (w.m_NumPoints * sizeof (dplane_t)); hlassume (planes != NULL, assume_NoMemory); numplanes = 0; for (x = 0; x < w.m_NumPoints; x++) { VectorSubtract (w.m_Points[(x + 1) % w.m_NumPoints], w.m_Points[x], v); CrossProduct (v, plane.normal, planes[numplanes].normal); if (!VectorNormalize (planes[numplanes].normal)) { continue; } planes[numplanes].dist = DotProduct (w.m_Points[x], planes[numplanes].normal); numplanes++; } bestwidth = 0; VectorCopy (point, bestpoint); newwidth = width; for (pass = 0; pass < 5; pass++) // apply binary search method for 5 iterations to find the maximal distance that the point can be kept away from all the edges { bool failed; vec3_t newpoint; Winding *newwinding; failed = true; newwinding = new Winding (w); for (x = 0; x < numplanes && newwinding->m_NumPoints > 0; x++) { dplane_t clipplane = planes[x]; clipplane.dist += newwidth; newwinding->Clip (clipplane, false); } if (newwinding->m_NumPoints > 0) { VectorCopy (point, newpoint); snap_to_winding (*newwinding, plane, newpoint); VectorSubtract (newpoint, point, v); if (VectorLength (v) <= maxmove + ON_EPSILON) { failed = false; } } delete newwinding; if (!failed) { bestwidth = newwidth; VectorCopy (newpoint, bestpoint); if (pass == 0) { break; } newwidth += width * pow (0.5, pass + 1); } else { newwidth -= width * pow (0.5, pass + 1); } } free (planes); VectorCopy (bestpoint, point); return bestwidth; }
void Winding::Divide(const dplane_t& split, Winding** front, Winding** back) { vec_t dists[MAX_POINTS_ON_WINDING]; int sides[MAX_POINTS_ON_WINDING]; int counts[3]; vec_t dot; int i, j; int maxpts; counts[0] = counts[1] = counts[2] = 0; // determine sides for each point for (i = 0; i < m_NumPoints; i++) { dot = DotProduct(m_Points[i], split.normal); dot -= split.dist; dists[i] = dot; if (dot > ON_EPSILON) { sides[i] = SIDE_FRONT; } else if (dot < -ON_EPSILON) { sides[i] = SIDE_BACK; } else { sides[i] = SIDE_ON; } counts[sides[i]]++; } sides[i] = sides[0]; dists[i] = dists[0]; *front = *back = NULL; if (!counts[0]) { *back = this; // Makes this function non-const return; } if (!counts[1]) { *front = this; // Makes this function non-const return; } maxpts = m_NumPoints + 4; // can't use counts[0]+2 because // of fp grouping errors Winding* f = new Winding(maxpts); Winding* b = new Winding(maxpts); *front = f; *back = b; f->m_NumPoints = 0; b->m_NumPoints = 0; for (i = 0; i < m_NumPoints; i++) { vec_t* p1 = m_Points[i]; if (sides[i] == SIDE_ON) { VectorCopy(p1, f->m_Points[f->m_NumPoints]); VectorCopy(p1, b->m_Points[b->m_NumPoints]); f->m_NumPoints++; b->m_NumPoints++; continue; } else if (sides[i] == SIDE_FRONT) { VectorCopy(p1, f->m_Points[f->m_NumPoints]); f->m_NumPoints++; } else if (sides[i] == SIDE_BACK) { VectorCopy(p1, b->m_Points[b->m_NumPoints]); b->m_NumPoints++; } if (sides[i + 1] == SIDE_ON || sides[i + 1] == sides[i]) { continue; } // generate a split point vec3_t mid; unsigned int tmp = i + 1; if (tmp >= m_NumPoints) { tmp = 0; } vec_t* p2 = m_Points[tmp]; dot = dists[i] / (dists[i] - dists[i + 1]); for (j = 0; j < 3; j++) { // avoid round off error when possible if (split.normal[j] < 1.0 - NORMAL_EPSILON) { if (split.normal[j] > -1.0 + NORMAL_EPSILON) { mid[j] = p1[j] + dot * (p2[j] - p1[j]); } else { mid[j] = -split.dist; } } else { mid[j] = split.dist; } } VectorCopy(mid, f->m_Points[f->m_NumPoints]); VectorCopy(mid, b->m_Points[b->m_NumPoints]); f->m_NumPoints++; b->m_NumPoints++; } if (f->m_NumPoints > maxpts || b->m_NumPoints > maxpts) { Error("Winding::Divide : points exceeded estimate"); } f->RemoveColinearPoints(); b->RemoveColinearPoints(); }
void Winding::Clip(const vec3_t normal, const vec_t dist, Winding** front, Winding** back) { vec_t dists[MAX_POINTS_ON_WINDING + 4]; int sides[MAX_POINTS_ON_WINDING + 4]; int counts[3]; vec_t dot; unsigned int i, j; unsigned int maxpts; counts[0] = counts[1] = counts[2] = 0; // determine sides for each point for (i = 0; i < m_NumPoints; i++) { dot = DotProduct(m_Points[i], normal); dot -= dist; dists[i] = dot; if (dot > ON_EPSILON) { sides[i] = SIDE_FRONT; } else if (dot < -ON_EPSILON) { sides[i] = SIDE_BACK; } else { sides[i] = SIDE_ON; } counts[sides[i]]++; } sides[i] = sides[0]; dists[i] = dists[0]; if (!counts[0]) { *front = NULL; *back = new Winding(*this); return; } if (!counts[1]) { *front = new Winding(*this); *back = NULL; return; } maxpts = m_NumPoints + 4; // can't use counts[0]+2 because // of fp grouping errors Winding* f = new Winding(maxpts); Winding* b = new Winding(maxpts); *front = f; *back = b; f->m_NumPoints = 0; b->m_NumPoints = 0; for (i = 0; i < m_NumPoints; i++) { vec_t* p1 = m_Points[i]; if (sides[i] == SIDE_ON) { VectorCopy(p1, f->m_Points[f->m_NumPoints]); VectorCopy(p1, b->m_Points[b->m_NumPoints]); f->m_NumPoints++; b->m_NumPoints++; continue; } else if (sides[i] == SIDE_FRONT) { VectorCopy(p1, f->m_Points[f->m_NumPoints]); f->m_NumPoints++; } else if (sides[i] == SIDE_BACK) { VectorCopy(p1, b->m_Points[b->m_NumPoints]); b->m_NumPoints++; } if ((sides[i + 1] == SIDE_ON) | (sides[i + 1] == sides[i])) // | instead of || for branch optimization { continue; } // generate a split point vec3_t mid; unsigned int tmp = i + 1; if (tmp >= m_NumPoints) { tmp = 0; } vec_t* p2 = m_Points[tmp]; dot = dists[i] / (dists[i] - dists[i + 1]); #if 0 for (j = 0; j < 3; j++) { // avoid round off error when possible if (normal[j] < 1.0 - NORMAL_EPSILON) { if (normal[j] > -1.0 + NORMAL_EPSILON) { mid[j] = p1[j] + dot * (p2[j] - p1[j]); } else { mid[j] = -dist; } } else { mid[j] = dist; } } #else for (j = 0; j < 3; j++) { // avoid round off error when possible if (normal[j] == 1) mid[j] = dist; else if (normal[j] == -1) mid[j] = -dist; else mid[j] = p1[j] + dot * (p2[j] - p1[j]); } #endif VectorCopy(mid, f->m_Points[f->m_NumPoints]); VectorCopy(mid, b->m_Points[b->m_NumPoints]); f->m_NumPoints++; b->m_NumPoints++; } if ((f->m_NumPoints > maxpts) | (b->m_NumPoints > maxpts)) // | instead of || for branch optimization { Error("Winding::Clip : points exceeded estimate"); } if ((f->m_NumPoints > MAX_POINTS_ON_WINDING) | (b->m_NumPoints > MAX_POINTS_ON_WINDING)) // | instead of || for branch optimization { Error("Winding::Clip : MAX_POINTS_ON_WINDING"); } f->RemoveColinearPoints(); b->RemoveColinearPoints(); }