1 Index: tools/quake3/q3map2/model.c
2 ===================================================================
3 --- tools/quake3/q3map2/model.c (revision 193)
4 +++ tools/quake3/q3map2/model.c (working copy)
9 + double normalEpsilon_save;
10 + double distanceEpsilon_save;
15 /* ydnar: giant hack land: generate clipping brushes for model triangles */
16 if( si->clipModel || (spawnFlags & 2) ) /* 2nd bit */
18 - vec3_t points[ 3 ], backs[ 3 ];
19 + vec3_t points[ 4 ], backs[ 3 ];
20 vec4_t plane, reverse, pa, pb, pc;
25 @@ -437,90 +438,141 @@
26 /* note: this doesn't work as well as simply using the plane of the triangle, below */
27 for( k = 0; k < 3; k++ )
29 - if( fabs( dv->normal[ k ] ) > fabs( dv->normal[ (k + 1) % 3 ] ) &&
30 - fabs( dv->normal[ k ] ) > fabs( dv->normal[ (k + 2) % 3 ] ) )
31 + if( fabs( dv->normal[ k ] ) >= fabs( dv->normal[ (k + 1) % 3 ] ) &&
32 + fabs( dv->normal[ k ] ) >= fabs( dv->normal[ (k + 2) % 3 ] ) )
34 backs[ j ][ k ] += dv->normal[ k ] < 0.0f ? 64.0f : -64.0f;
40 + VectorCopy( points[0], points[3] ); // for cyclic usage
42 /* make plane for triangle */
43 + // div0: add some extra spawnflags:
44 + // 0: snap normals to axial planes for extrusion
45 + // 8: extrude with the original normals
46 + // 16: extrude only with up/down normals (ideal for terrain)
47 + // 24: extrude by distance zero (may need engine changes)
48 if( PlaneFromPoints( plane, points[ 0 ], points[ 1 ], points[ 2 ] ) )
51 + float backPlaneDistance = 2;
53 + if(spawnFlags & 8) // use a DOWN normal
57 + // 24: normal as is, and zero width (broken)
58 + VectorCopy(plane, bestNormal);
63 + VectorCopy(plane, bestNormal);
70 + // 16: UP/DOWN normal
71 + VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
76 + if(fabs(plane[0]) > fabs(plane[1])) // x>y
77 + if(fabs(plane[1]) > fabs(plane[2])) // x>y, y>z
78 + VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0);
80 + if(fabs(plane[0]) > fabs(plane[2])) // x>z, z>=y
81 + VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0);
83 + VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
85 + if(fabs(plane[1]) > fabs(plane[2])) // y>z, y>=x
86 + VectorSet(bestNormal, 0, (plane[1] >= 0 ? 1 : -1), 0);
88 + VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
93 + buildBrush = AllocBrush( 48 );
94 + buildBrush->entityNum = mapEntityNum;
95 + buildBrush->original = buildBrush;
96 + buildBrush->contentShader = si;
97 + buildBrush->compileFlags = si->compileFlags;
98 + buildBrush->contentFlags = si->contentFlags;
99 + normalEpsilon_save = normalEpsilon;
100 + distanceEpsilon_save = distanceEpsilon;
101 + if(si->compileFlags & C_STRUCTURAL) // allow forced structural brushes here
103 + buildBrush->detail = qfalse;
105 + // only allow EXACT matches when snapping for these (this is mostly for caulk brushes inside a model)
106 + if(normalEpsilon > 0)
108 + if(distanceEpsilon > 0)
109 + distanceEpsilon = 0;
112 + buildBrush->detail = qtrue;
114 /* regenerate back points */
115 for( j = 0; j < 3; j++ )
118 dv = &ds->verts[ ds->indexes[ i + j ] ];
121 - VectorCopy( dv->xyz, backs[ j ] );
123 - /* find nearest axial to plane normal and push back points opposite */
124 - for( k = 0; k < 3; k++ )
126 - if( fabs( plane[ k ] ) > fabs( plane[ (k + 1) % 3 ] ) &&
127 - fabs( plane[ k ] ) > fabs( plane[ (k + 2) % 3 ] ) )
129 - backs[ j ][ k ] += plane[ k ] < 0.0f ? 64.0f : -64.0f;
134 + // shift by some units
135 + VectorMA(dv->xyz, -64.0f, bestNormal, backs[j]); // 64 prevents roundoff errors a bit
139 /* make back plane */
140 VectorScale( plane, -1.0f, reverse );
141 - reverse[ 3 ] = -(plane[ 3 ] - 1);
143 - /* make back pyramid point */
144 - VectorCopy( points[ 0 ], nadir );
145 - VectorAdd( nadir, points[ 1 ], nadir );
146 - VectorAdd( nadir, points[ 2 ], nadir );
147 - VectorScale( nadir, 0.3333333333333f, nadir );
148 - VectorMA( nadir, -2.0f, plane, nadir );
150 - /* make 3 more planes */
151 - //% if( PlaneFromPoints( pa, points[ 2 ], points[ 1 ], nadir ) &&
152 - //% PlaneFromPoints( pb, points[ 1 ], points[ 0 ], nadir ) &&
153 - //% PlaneFromPoints( pc, points[ 0 ], points[ 2 ], nadir ) )
154 + reverse[ 3 ] = -plane[ 3 ];
155 + if((spawnFlags & 24) != 24)
156 + reverse[3] += DotProduct(bestNormal, plane) * backPlaneDistance;
157 + // that's at least sqrt(1/3) backPlaneDistance, unless in DOWN mode; in DOWN mode, we are screwed anyway if we encounter a plane that's perpendicular to the xy plane)
159 if( PlaneFromPoints( pa, points[ 2 ], points[ 1 ], backs[ 1 ] ) &&
160 - PlaneFromPoints( pb, points[ 1 ], points[ 0 ], backs[ 0 ] ) &&
161 - PlaneFromPoints( pc, points[ 0 ], points[ 2 ], backs[ 2 ] ) )
162 + PlaneFromPoints( pb, points[ 1 ], points[ 0 ], backs[ 0 ] ) &&
163 + PlaneFromPoints( pc, points[ 0 ], points[ 2 ], backs[ 2 ] ) )
165 - /* build a brush */
166 - buildBrush = AllocBrush( 48 );
168 - buildBrush->entityNum = mapEntityNum;
169 - buildBrush->original = buildBrush;
170 - buildBrush->contentShader = si;
171 - buildBrush->compileFlags = si->compileFlags;
172 - buildBrush->contentFlags = si->contentFlags;
173 - buildBrush->detail = qtrue;
175 /* set up brush sides */
176 buildBrush->numsides = 5;
177 for( j = 0; j < buildBrush->numsides; j++ )
178 buildBrush->sides[ j ].shaderInfo = si;
180 buildBrush->sides[ 0 ].planenum = FindFloatPlane( plane, plane[ 3 ], 3, points );
181 - buildBrush->sides[ 1 ].planenum = FindFloatPlane( pa, pa[ 3 ], 1, &points[ 2 ] );
182 - buildBrush->sides[ 2 ].planenum = FindFloatPlane( pb, pb[ 3 ], 1, &points[ 1 ] );
183 - buildBrush->sides[ 3 ].planenum = FindFloatPlane( pc, pc[ 3 ], 1, &points[ 0 ] );
184 - buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 3, points );
186 - /* add to entity */
187 - if( CreateBrushWindings( buildBrush ) )
190 - //% EmitBrushes( buildBrush, NULL, NULL );
191 - buildBrush->next = entities[ mapEntityNum ].brushes;
192 - entities[ mapEntityNum ].brushes = buildBrush;
193 - entities[ mapEntityNum ].numBrushes++;
196 - free( buildBrush );
197 + buildBrush->sides[ 1 ].planenum = FindFloatPlane( pa, pa[ 3 ], 2, &points[ 1 ] ); // pa contains points[1] and points[2]
198 + buildBrush->sides[ 2 ].planenum = FindFloatPlane( pb, pb[ 3 ], 2, &points[ 0 ] ); // pb contains points[0] and points[1]
199 + buildBrush->sides[ 3 ].planenum = FindFloatPlane( pc, pc[ 3 ], 2, &points[ 2 ] ); // pc contains points[2] and points[0] (copied to points[3]
200 + buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 3, backs );
208 + normalEpsilon = normalEpsilon_save;
209 + distanceEpsilon = distanceEpsilon_save;
211 + /* add to entity */
212 + if( CreateBrushWindings( buildBrush ) )
215 + //% EmitBrushes( buildBrush, NULL, NULL );
216 + buildBrush->next = entities[ mapEntityNum ].brushes;
217 + entities[ mapEntityNum ].brushes = buildBrush;
218 + entities[ mapEntityNum ].numBrushes++;
221 + free( buildBrush );
225 Index: tools/quake3/q3map2/map.c
226 ===================================================================
227 --- tools/quake3/q3map2/map.c (revision 193)
228 +++ tools/quake3/q3map2/map.c (working copy)
230 snaps a plane to normal/distance epsilons
233 -void SnapPlane( vec3_t normal, vec_t *dist )
234 +void SnapPlane( vec3_t normal, vec_t *dist, vec3_t center )
236 // SnapPlane disabled by LordHavoc because it often messes up collision
237 // brushes made from triangles of embedded models, and it has little effect
239 SnapPlane reenabled by namespace because of multiple reports of
240 q3map2-crashes which were triggered by this patch.
242 + // div0: ensure the point "center" stays on the plane (actually, this
243 + // rotates the plane around the point center).
244 + // if center lies on the plane, it is guaranteed to stay on the plane by
246 + vec_t centerDist = DotProduct(normal, center);
247 SnapNormal( normal );
248 + *dist += (DotProduct(normal, center) - centerDist);
250 if( fabs( *dist - Q_rint( *dist ) ) < distanceEpsilon )
251 *dist = Q_rint( *dist );
253 must be within an epsilon distance of the plane
256 -int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points )
257 +int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points ) // NOTE: this has a side effect on the normal. Good or bad?
261 @@ -215,10 +221,14 @@
265 + vec3_t centerofweight;
267 + VectorClear(centerofweight);
268 + for(i = 0; i < numPoints; ++i)
269 + VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
273 - SnapPlane( normal, &dist );
274 + SnapPlane( normal, &dist, centerofweight );
275 hash = (PLANE_HASHES - 1) & (int) fabs( dist );
277 /* search the border bins as well */
282 - SnapPlane( normal, &dist );
283 + vec3_t centerofweight;
285 + VectorClear(centerofweight);
286 + for(i = 0; i < numPoints; ++i)
287 + VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
289 + SnapPlane( normal, &dist, centerofweight );
290 for( i = 0, p = mapplanes; i < nummapplanes; i++, p++ )
292 if( PlaneEqual( p, normal, dist ) )