static void R_Alias_clip_bottom(draw.finalvert_t pfv0, draw.finalvert_t pfv1, ref draw.finalvert_t @out) { double scale; int i; if (pfv0.v[1] >= pfv1.v[1]) { scale = (double)(r_refdef.aliasvrectbottom - pfv0.v[1]) / (pfv1.v[1] - pfv0.v[1]); for (i = 0; i < 6; i++) { @out.v[i] = (int)(pfv0.v[i] + (pfv1.v[i] - pfv0.v[i]) * scale + 0.5); } } else { scale = (double)(r_refdef.aliasvrectbottom - pfv1.v[1]) / (pfv0.v[1] - pfv1.v[1]); for (i = 0; i < 6; i++) { @out.v[i] = (int)(pfv1.v[i] + (pfv0.v[i] - pfv1.v[i]) * scale + 0.5); } } }
/* * ================ * R_Alias_clip_z * * pfv0 is the unclipped vertex, pfv1 is the z-clipped vertex * ================ */ static void R_Alias_clip_z(draw.finalvert_t pfv0, draw.finalvert_t pfv1, ref draw.finalvert_t @out) { double scale; auxvert_t pav0, pav1, avout = new auxvert_t(); pav0 = av[av0]; pav1 = av[av1]; if (pfv0.v[1] >= pfv1.v[1]) { scale = (ALIAS_Z_CLIP_PLANE - pav0.fv[2]) / (pav1.fv[2] - pav0.fv[2]); avout.fv[0] = pav0.fv[0] + (pav1.fv[0] - pav0.fv[0]) * scale; avout.fv[1] = pav0.fv[1] + (pav1.fv[1] - pav0.fv[1]) * scale; avout.fv[2] = ALIAS_Z_CLIP_PLANE; @out.v[2] = (int)(pfv0.v[2] + (pfv1.v[2] - pfv0.v[2]) * scale); @out.v[3] = (int)(pfv0.v[3] + (pfv1.v[3] - pfv0.v[3]) * scale); @out.v[4] = (int)(pfv0.v[4] + (pfv1.v[4] - pfv0.v[4]) * scale); } else { scale = (ALIAS_Z_CLIP_PLANE - pav1.fv[2]) / (pav0.fv[2] - pav1.fv[2]); avout.fv[0] = pav1.fv[0] + (pav0.fv[0] - pav1.fv[0]) * scale; avout.fv[1] = pav1.fv[1] + (pav0.fv[1] - pav1.fv[1]) * scale; avout.fv[2] = ALIAS_Z_CLIP_PLANE; @out.v[2] = (int)(pfv1.v[2] + (pfv0.v[2] - pfv1.v[2]) * scale); @out.v[3] = (int)(pfv1.v[3] + (pfv0.v[3] - pfv1.v[3]) * scale); @out.v[4] = (int)(pfv1.v[4] + (pfv0.v[4] - pfv1.v[4]) * scale); } R_AliasProjectFinalVert(@out, avout); if (@out.v[0] < r_refdef.aliasvrect.x) { @out.flags |= ALIAS_LEFT_CLIP; } if (@out.v[1] < r_refdef.aliasvrect.y) { @out.flags |= ALIAS_TOP_CLIP; } if (@out.v[0] > r_refdef.aliasvrectright) { @out.flags |= ALIAS_RIGHT_CLIP; } if (@out.v[1] > r_refdef.aliasvrectbottom) { @out.flags |= ALIAS_BOTTOM_CLIP; } }
/* * ================ * R_AliasTransformAndProjectFinalVerts * ================ */ static void R_AliasTransformAndProjectFinalVerts(draw.finalvert_t[] pfv, model.stvert_t[] pstverts) { int i, temp; double lightcos; double[] plightnormal; double zi; model.trivertx_t pverts; for (i = 0; i < r_anumverts; i++) { draw.finalvert_t fv = pfv[i]; model.stvert_t stverts = pstverts[i]; pverts = r_apverts[i]; // transform and project zi = 1.0 / (mathlib.DotProduct(pverts.v, aliastransform[2]) + aliastransform[2][3]); // x, y, and z are scaled down by 1/2**31 in the transform, so 1/z is // scaled up by 1/2**31, and the scaling cancels out for x and y in the // projection fv.v[5] = (int)zi; fv.v[0] = (int)(((mathlib.DotProduct(pverts.v, aliastransform[0]) + aliastransform[0][3]) * zi) + aliasxcenter); fv.v[1] = (int)(((mathlib.DotProduct(pverts.v, aliastransform[1]) + aliastransform[1][3]) * zi) + aliasycenter); fv.v[2] = stverts.s; fv.v[3] = stverts.t; fv.flags = stverts.onseam; // lighting plightnormal = r_avertexnormals[pverts.lightnormalindex]; lightcos = mathlib.DotProduct(plightnormal, r_plightvec); temp = r_ambientlight; if (lightcos < 0) { temp += (int)(r_shadelight * lightcos); // clamp; because we limited the minimum ambient and shading light, we // don't have to clamp low light, just bright if (temp < 0) { temp = 0; } } fv.v[4] = temp; } }
static void r_alias_init() { finalverts = new draw.finalvert_t[MAXALIASVERTS]; auxverts = new auxvert_t[MAXALIASVERTS]; for (int kk = 0; kk < MAXALIASVERTS; kk++) { finalverts[kk] = new draw.finalvert_t(); auxverts[kk] = new auxvert_t(); } }
/* * ================ * R_AliasProjectFinalVert * ================ */ static void R_AliasProjectFinalVert(draw.finalvert_t fv, auxvert_t av) { double zi; // project points zi = 1.0 / av.fv[2]; fv.v[5] = (int)(zi * ziscale); fv.v[0] = (int)((av.fv[0] * aliasxscale * zi) + aliasxcenter); fv.v[1] = (int)((av.fv[1] * aliasyscale * zi) + aliasycenter); }
/* * ================ * R_AliasTransformFinalVert * ================ */ static void R_AliasTransformFinalVert(draw.finalvert_t fv, auxvert_t av, model.trivertx_t pverts, model.stvert_t pstverts) { int temp; double lightcos; double[] plightnormal; av.fv[0] = mathlib.DotProduct(pverts.v, aliastransform[0]) + aliastransform[0][3]; av.fv[1] = mathlib.DotProduct(pverts.v, aliastransform[1]) + aliastransform[1][3]; av.fv[2] = mathlib.DotProduct(pverts.v, aliastransform[2]) + aliastransform[2][3]; fv.v[2] = pstverts.s; fv.v[3] = pstverts.t; fv.flags = pstverts.onseam; // lighting plightnormal = r_avertexnormals[pverts.lightnormalindex]; lightcos = mathlib.DotProduct(plightnormal, r_plightvec); temp = r_ambientlight; if (lightcos < 0) { temp += (int)(r_shadelight * lightcos); // clamp; because we limited the minimum ambient and shading light, we // don't have to clamp low light, just bright if (temp < 0) { temp = 0; } } fv.v[4] = temp; }
/* ================ R_AliasPreparePoints General clipped case ================ */ static void R_AliasPreparePoints() { int i; model.stvert_t[] pstverts; draw.finalvert_t fv; auxvert_t av; model.mtriangle_t ptri; draw.finalvert_t[] pfv = new draw.finalvert_t[3]; pstverts = (model.stvert_t[])paliashdr.stverts; r_anumverts = pmdl.numverts; for (i=0 ; i<r_anumverts ; i++) { fv = pfinalverts[i]; av = pauxverts[i]; R_AliasTransformFinalVert (fv, av, r_apverts[i], pstverts[i]); if (av.fv[2] < ALIAS_Z_CLIP_PLANE) fv.flags |= ALIAS_Z_CLIP; else { R_AliasProjectFinalVert (fv, av); if (fv.v[0] < r_refdef.aliasvrect.x) fv.flags |= ALIAS_LEFT_CLIP; if (fv.v[1] < r_refdef.aliasvrect.y) fv.flags |= ALIAS_TOP_CLIP; if (fv.v[0] > r_refdef.aliasvrectright) fv.flags |= ALIAS_RIGHT_CLIP; if (fv.v[1] > r_refdef.aliasvrectbottom) fv.flags |= ALIAS_BOTTOM_CLIP; } } // // clip and draw all triangles // r_affinetridesc.numtriangles = 1; for (i=0 ; i<pmdl.numtris ; i++) { ptri = (model.mtriangle_t)paliashdr.triangles[i]; pfv[0] = pfinalverts[ptri.vertindex[0]]; pfv[1] = pfinalverts[ptri.vertindex[1]]; pfv[2] = pfinalverts[ptri.vertindex[2]]; if (( pfv[0].flags & pfv[1].flags & pfv[2].flags & (ALIAS_XY_CLIP_MASK | ALIAS_Z_CLIP) ) != 0) continue; // completely clipped if ( ( (pfv[0].flags | pfv[1].flags | pfv[2].flags) & (ALIAS_XY_CLIP_MASK | ALIAS_Z_CLIP) ) == 0 ) { // totally unclipped r_affinetridesc.pfinalverts = pfinalverts; r_affinetridesc.ptriangles = new model.mtriangle_t[] { ptri }; draw.D_PolysetDraw (); } else { // partially clipped R_AliasClipTriangle (ptri); } } }
/* ================ R_AliasCheckBBox ================ */ static bool R_AliasCheckBBox() { int i, flags, frame, numv; model.aliashdr_t pahdr; double zi, v0, v1, frac; double[][] basepts = new double[8][]; draw.finalvert_t pv0, pv1; draw.finalvert_t[] viewpts = new draw.finalvert_t[16]; auxvert_t pa0, pa1; auxvert_t[] viewaux = new auxvert_t[16]; model.maliasframedesc_t pframedesc; bool zclipped, zfullyclipped; uint anyclip, allclip; int minz; int kk; for (kk = 0; kk < 16; kk++) viewpts[kk] = new draw.finalvert_t(); for (kk = 0; kk < 16; kk++) viewaux[kk] = new auxvert_t(); for (kk = 0; kk < 8; kk++) basepts[kk] = new double[3]; // expand, rotate, and translate points into worldspace currententity.trivial_accept = 0; pmodel = currententity.model; pahdr = (model.aliashdr_t)model.Mod_Extradata (pmodel); pmdl = (model.mdl_t)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)) { console.Con_DPrintf ("No such frame " + frame + " " + pmodel.name + "\n"); frame = 0; } pframedesc = pahdr.frames[frame]; // x worldspace coordinates basepts[0][0] = basepts[1][0] = basepts[2][0] = basepts[3][0] = (double)pframedesc.bboxmin.v[0]; basepts[4][0] = basepts[5][0] = basepts[6][0] = basepts[7][0] = (double)pframedesc.bboxmax.v[0]; // y worldspace coordinates basepts[0][1] = basepts[3][1] = basepts[5][1] = basepts[6][1] = (double)pframedesc.bboxmin.v[1]; basepts[1][1] = basepts[2][1] = basepts[4][1] = basepts[7][1] = (double)pframedesc.bboxmax.v[1]; // z worldspace coordinates basepts[0][2] = basepts[1][2] = basepts[4][2] = basepts[5][2] = (double)pframedesc.bboxmin.v[2]; basepts[2][2] = basepts[3][2] = basepts[6][2] = basepts[7][2] = (double)pframedesc.bboxmax.v[2]; zclipped = false; zfullyclipped = true; minz = 9999; for (i=0; i<8 ; i++) { R_AliasTransformVector (basepts[i], ref viewaux[i].fv); 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 = (int)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) != 0) { 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) != 0) 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 |= (uint)flags; allclip &= (uint)flags; } if (allclip != 0) return false; // trivial reject off one side currententity.trivial_accept = ((anyclip == 0) && !zclipped) ? 1 : 0; if (currententity.trivial_accept != 0) { if (minz > (r_aliastransition + (pmdl.size * r_resfudge))) { currententity.trivial_accept |= 2; } } return true; }
/* * ================ * R_AliasPreparePoints * * General clipped case * ================ */ static void R_AliasPreparePoints() { int i; model.stvert_t[] pstverts; draw.finalvert_t fv; auxvert_t av; model.mtriangle_t ptri; draw.finalvert_t[] pfv = new draw.finalvert_t[3]; pstverts = (model.stvert_t[])paliashdr.stverts; r_anumverts = pmdl.numverts; for (i = 0; i < r_anumverts; i++) { fv = pfinalverts[i]; av = pauxverts[i]; R_AliasTransformFinalVert(fv, av, r_apverts[i], pstverts[i]); if (av.fv[2] < ALIAS_Z_CLIP_PLANE) { fv.flags |= ALIAS_Z_CLIP; } else { R_AliasProjectFinalVert(fv, av); if (fv.v[0] < r_refdef.aliasvrect.x) { fv.flags |= ALIAS_LEFT_CLIP; } if (fv.v[1] < r_refdef.aliasvrect.y) { fv.flags |= ALIAS_TOP_CLIP; } if (fv.v[0] > r_refdef.aliasvrectright) { fv.flags |= ALIAS_RIGHT_CLIP; } if (fv.v[1] > r_refdef.aliasvrectbottom) { fv.flags |= ALIAS_BOTTOM_CLIP; } } } // // clip and draw all triangles // r_affinetridesc.numtriangles = 1; for (i = 0; i < pmdl.numtris; i++) { ptri = (model.mtriangle_t)paliashdr.triangles[i]; pfv[0] = pfinalverts[ptri.vertindex[0]]; pfv[1] = pfinalverts[ptri.vertindex[1]]; pfv[2] = pfinalverts[ptri.vertindex[2]]; if ((pfv[0].flags & pfv[1].flags & pfv[2].flags & (ALIAS_XY_CLIP_MASK | ALIAS_Z_CLIP)) != 0) { continue; // completely clipped } if (((pfv[0].flags | pfv[1].flags | pfv[2].flags) & (ALIAS_XY_CLIP_MASK | ALIAS_Z_CLIP)) == 0) { // totally unclipped r_affinetridesc.pfinalverts = pfinalverts; r_affinetridesc.ptriangles = new model.mtriangle_t[] { ptri }; draw.D_PolysetDraw(); } else { // partially clipped R_AliasClipTriangle(ptri); } } }
/* * ================ * R_AliasCheckBBox * ================ */ static bool R_AliasCheckBBox() { int i, flags, frame, numv; model.aliashdr_t pahdr; double zi, v0, v1, frac; double[][] basepts = new double[8][]; draw.finalvert_t pv0, pv1; draw.finalvert_t[] viewpts = new draw.finalvert_t[16]; auxvert_t pa0, pa1; auxvert_t[] viewaux = new auxvert_t[16]; model.maliasframedesc_t pframedesc; bool zclipped, zfullyclipped; uint anyclip, allclip; int minz; int kk; for (kk = 0; kk < 16; kk++) { viewpts[kk] = new draw.finalvert_t(); } for (kk = 0; kk < 16; kk++) { viewaux[kk] = new auxvert_t(); } for (kk = 0; kk < 8; kk++) { basepts[kk] = new double[3]; } // expand, rotate, and translate points into worldspace currententity.trivial_accept = 0; pmodel = currententity.model; pahdr = (model.aliashdr_t)model.Mod_Extradata(pmodel); pmdl = (model.mdl_t)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)) { console.Con_DPrintf("No such frame " + frame + " " + pmodel.name + "\n"); frame = 0; } pframedesc = pahdr.frames[frame]; // x worldspace coordinates basepts[0][0] = basepts[1][0] = basepts[2][0] = basepts[3][0] = (double)pframedesc.bboxmin.v[0]; basepts[4][0] = basepts[5][0] = basepts[6][0] = basepts[7][0] = (double)pframedesc.bboxmax.v[0]; // y worldspace coordinates basepts[0][1] = basepts[3][1] = basepts[5][1] = basepts[6][1] = (double)pframedesc.bboxmin.v[1]; basepts[1][1] = basepts[2][1] = basepts[4][1] = basepts[7][1] = (double)pframedesc.bboxmax.v[1]; // z worldspace coordinates basepts[0][2] = basepts[1][2] = basepts[4][2] = basepts[5][2] = (double)pframedesc.bboxmin.v[2]; basepts[2][2] = basepts[3][2] = basepts[6][2] = basepts[7][2] = (double)pframedesc.bboxmax.v[2]; zclipped = false; zfullyclipped = true; minz = 9999; for (i = 0; i < 8; i++) { R_AliasTransformVector(basepts[i], ref viewaux[i].fv); 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 = (int)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) != 0) { 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) != 0) { 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 |= (uint)flags; allclip &= (uint)flags; } if (allclip != 0) { return(false); // trivial reject off one side } currententity.trivial_accept = ((anyclip == 0) && !zclipped) ? 1 : 0; if (currententity.trivial_accept != 0) { if (minz > (r_aliastransition + (pmdl.size * r_resfudge))) { currententity.trivial_accept |= 2; } } return(true); }