/* ================ R_AliasCheckBBox ================ */ qboolean R_AliasCheckBBox(void) { int i, flags, frame, numv; aliashdr_t *pahdr; float zi, basepts[8][3], v0, v1, frac; finalvert_t *pv0, *pv1, viewpts[16]; auxvert_t *pa0, *pa1, viewaux[16]; maliasframedesc_t *pframedesc; qboolean zclipped, zfullyclipped; unsigned anyclip, allclip; int minz; // expand, rotate, and translate points into worldspace currententity->trivial_accept = 0; pmodel = currententity->model; pahdr = Mod_Extradata(pmodel); pmdl = (mdl_t *)((byte *)pahdr + pahdr->model); R_AliasSetUpTransform(0); // construct the base bounding box for this frame frame = currententity->frame; // TODO: don't repeat this check when drawing? if ((frame >= pmdl->numframes) || (frame < 0)) { Con_DPrintf("No such frame %d %s\n", frame, pmodel->name); frame = 0; } pframedesc = &pahdr->frames[frame]; // x worldspace coordinates basepts[0][0] = basepts[1][0] = basepts[2][0] = basepts[3][0] = (float)pframedesc->bboxmin.v[0]; basepts[4][0] = basepts[5][0] = basepts[6][0] = basepts[7][0] = (float)pframedesc->bboxmax.v[0]; // y worldspace coordinates basepts[0][1] = basepts[3][1] = basepts[5][1] = basepts[6][1] = (float)pframedesc->bboxmin.v[1]; basepts[1][1] = basepts[2][1] = basepts[4][1] = basepts[7][1] = (float)pframedesc->bboxmax.v[1]; // z worldspace coordinates basepts[0][2] = basepts[1][2] = basepts[4][2] = basepts[5][2] = (float)pframedesc->bboxmin.v[2]; basepts[2][2] = basepts[3][2] = basepts[6][2] = basepts[7][2] = (float)pframedesc->bboxmax.v[2]; zclipped = false; zfullyclipped = true; minz = 9999; for (i=0; i<8 ; i++) { R_AliasTransformVector(&basepts[i][0], &viewaux[i].fv[0]); if (viewaux[i].fv[2] < ALIAS_Z_CLIP_PLANE) { // we must clip points that are closer than the near clip plane viewpts[i].flags = ALIAS_Z_CLIP; zclipped = true; } else { if (viewaux[i].fv[2] < minz) { minz = viewaux[i].fv[2]; } viewpts[i].flags = 0; zfullyclipped = false; } } if (zfullyclipped) { return false; // everything was near-z-clipped } numv = 8; if (zclipped) { // organize points by edges, use edges to get new points (possible trivial // reject) for (i=0 ; i<12 ; i++) { // edge endpoints pv0 = &viewpts[aedges[i].index0]; pv1 = &viewpts[aedges[i].index1]; pa0 = &viewaux[aedges[i].index0]; pa1 = &viewaux[aedges[i].index1]; // if one end is clipped and the other isn't, make a new point if (pv0->flags ^ pv1->flags) { frac = (ALIAS_Z_CLIP_PLANE - pa0->fv[2]) / (pa1->fv[2] - pa0->fv[2]); viewaux[numv].fv[0] = pa0->fv[0] + (pa1->fv[0] - pa0->fv[0]) * frac; viewaux[numv].fv[1] = pa0->fv[1] + (pa1->fv[1] - pa0->fv[1]) * frac; viewaux[numv].fv[2] = ALIAS_Z_CLIP_PLANE; viewpts[numv].flags = 0; numv++; } } } // project the vertices that remain after clipping anyclip = 0; allclip = ALIAS_XY_CLIP_MASK; // TODO: probably should do this loop in ASM, especially if we use floats for (i=0 ; i<numv ; i++) { // we don't need to bother with vertices that were z-clipped if (viewpts[i].flags & ALIAS_Z_CLIP) { continue; } zi = 1.0 / viewaux[i].fv[2]; // FIXME: do with chop mode in ASM, or convert to float v0 = (viewaux[i].fv[0] * xscale * zi) + xcenter; v1 = (viewaux[i].fv[1] * yscale * zi) + ycenter; flags = 0; if (v0 < r_refdef.fvrectx) { flags |= ALIAS_LEFT_CLIP; } if (v1 < r_refdef.fvrecty) { flags |= ALIAS_TOP_CLIP; } if (v0 > r_refdef.fvrectright) { flags |= ALIAS_RIGHT_CLIP; } if (v1 > r_refdef.fvrectbottom) { flags |= ALIAS_BOTTOM_CLIP; } anyclip |= flags; allclip &= flags; } if (allclip) { return false; // trivial reject off one side } currententity->trivial_accept = !anyclip & !zclipped; if (currententity->trivial_accept) { if (minz > (r_aliastransition + (pmdl->size * r_resfudge))) { currententity->trivial_accept |= 2; } } return true; }
/* ** R_AliasCheckFrameBBox ** ** Checks a specific alias frame bounding box */ static unsigned long R_AliasCheckFrameBBox( daliasframe_t *frame, float worldxf[3][4] ) { unsigned long aggregate_and_clipcode = ~0U, aggregate_or_clipcode = 0; int i; vec3_t mins, maxs; vec3_t transformed_min, transformed_max; qboolean zclipped = false, zfullyclipped = true; /* ** get the exact frame bounding box */ for (i=0 ; i<3 ; i++) { mins[i] = frame->translate[i]; maxs[i] = mins[i] + frame->scale[i]*255; } /* ** transform the min and max values into view space */ R_AliasTransformVector( mins, transformed_min, aliastransform ); R_AliasTransformVector( maxs, transformed_max, aliastransform ); if ( transformed_min[2] >= ALIAS_Z_CLIP_PLANE ) zfullyclipped = false; if ( transformed_max[2] >= ALIAS_Z_CLIP_PLANE ) zfullyclipped = false; if ( zfullyclipped ) { return BBOX_TRIVIAL_REJECT; } if ( zclipped ) { return ( BBOX_MUST_CLIP_XY | BBOX_MUST_CLIP_Z ); } /* ** build a transformed bounding box from the given min and max */ for ( i = 0; i < 8; i++ ) { int j; vec3_t tmp, transformed; unsigned long clipcode = 0; if ( i & 1 ) tmp[0] = mins[0]; else tmp[0] = maxs[0]; if ( i & 2 ) tmp[1] = mins[1]; else tmp[1] = maxs[1]; if ( i & 4 ) tmp[2] = mins[2]; else tmp[2] = maxs[2]; R_AliasTransformVector( tmp, transformed, worldxf ); for ( j = 0; j < 4; j++ ) { float dp = DotProduct( transformed, view_clipplanes[j].normal ); if ( ( dp - view_clipplanes[j].dist ) < 0.0F ) clipcode |= 1 << j; } aggregate_and_clipcode &= clipcode; aggregate_or_clipcode |= clipcode; } if ( aggregate_and_clipcode ) { return BBOX_TRIVIAL_REJECT; } if ( !aggregate_or_clipcode ) { return BBOX_TRIVIAL_ACCEPT; } return BBOX_MUST_CLIP_XY; }