/* ==================== SplitMeshByPlane ==================== */ void SplitMeshByPlane(mesh_t * in, vec3_t normal, float dist, mesh_t ** front, mesh_t ** back) { int w, h, split; float d[MAX_PATCH_SIZE][MAX_PATCH_SIZE]; drawVert_t *dv, *v1, *v2; int c_front, c_back, c_on; mesh_t *f, *b; int i; float frac; int frontAprox, backAprox; for(i = 0; i < 2; i++) { dv = in->verts; c_front = 0; c_back = 0; c_on = 0; for(h = 0; h < in->height; h++) { for(w = 0; w < in->width; w++, dv++) { d[h][w] = DotProduct(dv->xyz, normal) - dist; if(d[h][w] > ON_EPSILON) { c_front++; } else if(d[h][w] < -ON_EPSILON) { c_back++; } else { c_on++; } } } *front = NULL; *back = NULL; if(!c_front) { *back = in; return; } if(!c_back) { *front = in; return; } // find a split point split = -1; for(w = 0; w < in->width - 1; w++) { if((d[0][w] < 0) != (d[0][w + 1] < 0)) { if(split == -1) { split = w; break; } } } if(split == -1) { if(i == 1) { Sys_FPrintf(SYS_VRB, "No crossing points in patch\n"); *front = in; return; } in = TransposeMesh(in); InvertMesh(in); continue; } // make sure the split point stays the same for all other rows for(h = 1; h < in->height; h++) { for(w = 0; w < in->width - 1; w++) { if((d[h][w] < 0) != (d[h][w + 1] < 0)) { if(w != split) { Sys_Printf("multiple crossing points for patch -- can't clip\n"); *front = in; return; } } } if((d[h][split] < 0) == (d[h][split + 1] < 0)) { Sys_Printf("differing crossing points for patch -- can't clip\n"); *front = in; return; } } break; } // create two new meshes f = malloc(sizeof(*f)); f->width = split + 2; if(!(f->width & 1)) { f->width++; frontAprox = 1; } else { frontAprox = 0; } if(f->width > MAX_PATCH_SIZE) { Error("MAX_PATCH_SIZE after split"); } f->height = in->height; f->verts = malloc(sizeof(f->verts[0]) * f->width * f->height); b = malloc(sizeof(*b)); b->width = in->width - split; if(!(b->width & 1)) { b->width++; backAprox = 1; } else { backAprox = 0; } if(b->width > MAX_PATCH_SIZE) { Error("MAX_PATCH_SIZE after split"); } b->height = in->height; b->verts = malloc(sizeof(b->verts[0]) * b->width * b->height); if(d[0][0] > 0) { *front = f; *back = b; } else { *front = b; *back = f; } // distribute the points for(w = 0; w < in->width; w++) { for(h = 0; h < in->height; h++) { if(w <= split) { f->verts[h * f->width + w] = in->verts[h * in->width + w]; } else { b->verts[h * b->width + w - split + backAprox] = in->verts[h * in->width + w]; } } } // clip the crossing line for(h = 0; h < in->height; h++) { dv = &f->verts[h * f->width + split + 1]; v1 = &in->verts[h * in->width + split]; v2 = &in->verts[h * in->width + split + 1]; frac = d[h][split] / (d[h][split] - d[h][split + 1]); for(i = 0; i < 10; i++) { dv->xyz[i] = v1->xyz[i] + frac * (v2->xyz[i] - v1->xyz[i]); } dv->xyz[10] = 0; //set all 4 colors to 0 if(frontAprox) { f->verts[h * f->width + split + 2] = *dv; } b->verts[h * b->width] = *dv; if(backAprox) { b->verts[h * b->width + 1] = *dv; } } /* PrintMesh( in ); Sys_Printf("\n"); PrintMesh( f ); Sys_Printf("\n"); PrintMesh( b ); Sys_Printf("\n"); */ FreeMesh(in); }
qboolean ChopPatchSurfaceByBrush( entity_t *e, mapDrawSurface_t *ds, brush_t *b ){ int i, j; side_t *s; plane_t *plane; mesh_t *outside[MAX_BRUSH_SIDES]; int numOutside; mesh_t *m, *front, *back; mapDrawSurface_t *newds; m = DrawSurfToMesh( ds ); numOutside = 0; // only split by the top and bottom planes to avoid // some messy patch clipping issues for ( i = 4 ; i <= 5 ; i++ ) { s = &b->sides[ i ]; plane = &mapplanes[ s->planenum ]; SplitMeshByPlane( m, plane->normal, plane->dist, &front, &back ); if ( !back ) { // nothing actually contained inside for ( j = 0 ; j < numOutside ; j++ ) { FreeMesh( outside[j] ); } return qfalse; } m = back; if ( front ) { if ( numOutside == MAX_BRUSH_SIDES ) { Error( "MAX_BRUSH_SIDES" ); } outside[ numOutside ] = front; numOutside++; } } /* all of outside fragments become seperate drawsurfs */ numFogPatchFragments += numOutside; for ( i = 0; i < numOutside; i++ ) { /* transpose and invert the chopped patch (fixes potential crash. fixme: why?) */ outside[ i ] = TransposeMesh( outside[ i ] ); InvertMesh( outside[ i ] ); /* ydnar: do this the hacky right way */ newds = AllocDrawSurface( SURFACE_PATCH ); memcpy( newds, ds, sizeof( *ds ) ); newds->patchWidth = outside[ i ]->width; newds->patchHeight = outside[ i ]->height; newds->numVerts = outside[ i ]->width * outside[ i ]->height; newds->verts = safe_malloc( newds->numVerts * sizeof( *newds->verts ) ); memcpy( newds->verts, outside[ i ]->verts, newds->numVerts * sizeof( *newds->verts ) ); /* free the source mesh */ FreeMesh( outside[ i ] ); } /* only rejigger this patch if it was chopped */ //% Sys_Printf( "Inside: %d x %d\n", m->width, m->height ); if ( numOutside > 0 ) { /* transpose and invert the chopped patch (fixes potential crash. fixme: why?) */ m = TransposeMesh( m ); InvertMesh( m ); /* replace ds with m */ ds->patchWidth = m->width; ds->patchHeight = m->height; ds->numVerts = m->width * m->height; free( ds->verts ); ds->verts = safe_malloc( ds->numVerts * sizeof( *ds->verts ) ); memcpy( ds->verts, m->verts, ds->numVerts * sizeof( *ds->verts ) ); } /* free the source mesh and return */ FreeMesh( m ); return qtrue; }