/* * ============== * D_CalcGradients * ============== */ static void D_CalcGradients(model.msurface_t pface) { model.mplane_t pplane; double mipscale; double[] p_temp1 = new double[3]; double[] p_saxis = new double[3], p_taxis = new double[3]; double t; pplane = pface.plane; mipscale = 1.0 / (double)(1 << miplevel); render.TransformVector(pface.texinfo.vecs[0], ref p_saxis); render.TransformVector(pface.texinfo.vecs[1], ref p_taxis); t = render.xscaleinv * mipscale; d_sdivzstepu = p_saxis[0] * t; d_tdivzstepu = p_taxis[0] * t; t = render.yscaleinv * mipscale; d_sdivzstepv = -p_saxis[1] * t; d_tdivzstepv = -p_taxis[1] * t; d_sdivzorigin = p_saxis[2] * mipscale - render.xcenter * d_sdivzstepu - render.ycenter * d_sdivzstepv; d_tdivzorigin = p_taxis[2] * mipscale - render.xcenter * d_tdivzstepu - render.ycenter * d_tdivzstepv; mathlib.VectorScale(transformed_modelorg, mipscale, ref p_temp1); t = 0x10000 * mipscale; sadjust = ((int)(mathlib.DotProduct(p_temp1, p_saxis) * 0x10000 + 0.5)) - ((pface.texturemins[0] << 16) >> miplevel) + (int)(pface.texinfo.vecs[0][3] * t); tadjust = ((int)(mathlib.DotProduct(p_temp1, p_taxis) * 0x10000 + 0.5)) - ((pface.texturemins[1] << 16) >> miplevel) + (int)(pface.texinfo.vecs[1][3] * t); // // -1 (-epsilon) so we never wander off the edge of the texture // bbextents = ((pface.extents[0] << 16) >> miplevel) - 1; bbextentt = ((pface.extents[1] << 16) >> miplevel) - 1; }
/* * ================ * R_RenderPoly * ================ */ static void R_RenderPoly(model.msurface_t fa, int clipflags) { }
/* * ================ * R_RenderBmodelFace * ================ */ static void R_RenderBmodelFace(bedge_t pedges, model.msurface_t psurf) { int i; uint mask; model.mplane_t pplane; double distinv; double[] p_normal = new double[3]; model.medge_t tedge = new model.medge_t(); clipplane_t pclip; // skip out if no more surfs if (surface_p >= surf_max) { r_outofsurfaces++; return; } // ditto if not enough edges left, or switch to auxedges if possible if ((edge_p + psurf.numedges + 4) >= edge_max) { r_outofedges += psurf.numedges; return; } c_faceclip++; // this is a dummy to give the caching mechanism someplace to write to r_pedge = tedge; // set up clip planes pclip = null; for (i = 3, mask = 0x08; i >= 0; i--, mask >>= 1) { if ((r_clipflags & mask) != 0) { view_clipplanes[i].next = pclip; pclip = view_clipplanes[i]; } } // push the edges through r_emitted = 0; r_nearzi = 0; r_nearzionly = false; makeleftedge = makerightedge = false; // FIXME: keep clipped bmodel edges in clockwise order so last vertex caching // can be used? r_lastvertvalid = false; for ( ; pedges != null; pedges = pedges.pnext) { r_leftclipped = r_rightclipped = false; R_ClipEdge(pedges.v[0], pedges.v[1], pclip); if (r_leftclipped) { makeleftedge = true; } if (r_rightclipped) { makerightedge = true; } } // if there was a clip off the left edge, add that edge too // FIXME: faster to do in screen space? // FIXME: share clipped edges? if (makeleftedge) { r_pedge = tedge; R_ClipEdge(r_leftexit, r_leftenter, pclip.next); } // if there was a clip off the right edge, get the right r_nearzi if (makerightedge) { r_pedge = tedge; r_nearzionly = true; R_ClipEdge(r_rightexit, r_rightenter, view_clipplanes[1].next); } // if no edges made it out, return without posting the surface if (r_emitted == 0) { return; } r_polycount++; surfaces[surface_p].data = psurf; surfaces[surface_p].nearzi = r_nearzi; surfaces[surface_p].flags = psurf.flags; surfaces[surface_p].insubmodel = true; surfaces[surface_p].spanstate = 0; surfaces[surface_p].entity = currententity; surfaces[surface_p].key = r_currentbkey; surfaces[surface_p].spans = null; pplane = psurf.plane; // FIXME: cache this? TransformVector(pplane.normal, ref p_normal); // FIXME: cache this? distinv = 1.0 / (pplane.dist - mathlib.DotProduct(modelorg, pplane.normal)); surfaces[surface_p].d_zistepu = p_normal[0] * xscaleinv * distinv; surfaces[surface_p].d_zistepv = -p_normal[1] * yscaleinv * distinv; surfaces[surface_p].d_ziorigin = p_normal[2] * distinv - xcenter * surfaces[surface_p].d_zistepu - ycenter * surfaces[surface_p].d_zistepv; //JDC VectorCopy (r_worldmodelorg, surface_p.modelorg); surface_p++; }
/* * ================ * R_RenderFace * ================ */ static void R_RenderFace(model.msurface_t fa, int clipflags) { int i, lindex; uint mask; model.mplane_t pplane; double distinv; double[] p_normal = new double[3]; model.medge_t[] pedges; model.medge_t tedge = new model.medge_t(); clipplane_t pclip; // skip out if no more surfs if ((surface_p) >= surf_max) { r_outofsurfaces++; return; } // ditto if not enough edges left, or switch to auxedges if possible if ((edge_p + fa.numedges + 4) >= edge_max) { r_outofedges += fa.numedges; return; } c_faceclip++; // set up clip planes pclip = null; for (i = 3, mask = 0x08; i >= 0; i--, mask >>= 1) { if ((clipflags & mask) != 0) { view_clipplanes[i].next = pclip; pclip = view_clipplanes[i]; } } // push the edges through r_emitted = 0; r_nearzi = 0; r_nearzionly = false; makeleftedge = makerightedge = false; pedges = currententity.model.edges; r_lastvertvalid = false; for (i = 0; i < fa.numedges; i++) { lindex = currententity.model.surfedges[fa.firstedge + i]; if (lindex > 0) { r_pedge = pedges[lindex]; // if the edge is cached, we can just reuse the edge if (!insubmodel) { if ((r_pedge.cachededgeoffset & FULLY_CLIPPED_CACHED) != 0) { if ((r_pedge.cachededgeoffset & FRAMECOUNT_MASK) == r_framecount) { r_lastvertvalid = false; continue; } } else { if ((edge_p > r_pedge.cachededgeoffset) && (r_edges[r_pedge.cachededgeoffset].owner == r_pedge)) { R_EmitCachedEdge(); r_lastvertvalid = false; continue; } } } // assume it's cacheable cacheoffset = (uint)edge_p; r_leftclipped = r_rightclipped = false; R_ClipEdge(r_pcurrentvertbase[r_pedge.v[0]], r_pcurrentvertbase[r_pedge.v[1]], pclip); r_pedge.cachededgeoffset = cacheoffset; if (r_leftclipped) { makeleftedge = true; } if (r_rightclipped) { makerightedge = true; } r_lastvertvalid = true; } else { lindex = -lindex; r_pedge = pedges[lindex]; // if the edge is cached, we can just reuse the edge if (!insubmodel) { if ((r_pedge.cachededgeoffset & FULLY_CLIPPED_CACHED) != 0) { if ((r_pedge.cachededgeoffset & FRAMECOUNT_MASK) == r_framecount) { r_lastvertvalid = false; continue; } } else { // it's cached if the cached edge is valid and is owned // by this medge_t if ((edge_p > r_pedge.cachededgeoffset) && (r_edges[r_pedge.cachededgeoffset].owner == r_pedge)) { R_EmitCachedEdge(); r_lastvertvalid = false; continue; } } } // assume it's cacheable cacheoffset = (uint)edge_p; r_leftclipped = r_rightclipped = false; R_ClipEdge(r_pcurrentvertbase[r_pedge.v[1]], r_pcurrentvertbase[r_pedge.v[0]], pclip); r_pedge.cachededgeoffset = cacheoffset; if (r_leftclipped) { makeleftedge = true; } if (r_rightclipped) { makerightedge = true; } r_lastvertvalid = true; } } // if there was a clip off the left edge, add that edge too // FIXME: faster to do in screen space? // FIXME: share clipped edges? if (makeleftedge) { r_pedge = tedge; r_lastvertvalid = false; R_ClipEdge(r_leftexit, r_leftenter, pclip.next); } // if there was a clip off the right edge, get the right r_nearzi if (makerightedge) { r_pedge = tedge; r_lastvertvalid = false; r_nearzionly = true; R_ClipEdge(r_rightexit, r_rightenter, view_clipplanes[1].next); } // if no edges made it out, return without posting the surface if (r_emitted == 0) { return; } r_polycount++; surfaces[surface_p].data = fa; surfaces[surface_p].nearzi = r_nearzi; surfaces[surface_p].flags = fa.flags; surfaces[surface_p].insubmodel = insubmodel; surfaces[surface_p].spanstate = 0; surfaces[surface_p].entity = currententity; surfaces[surface_p].key = r_currentkey++; surfaces[surface_p].spans = null; pplane = fa.plane; // FIXME: cache this? TransformVector(pplane.normal, ref p_normal); // FIXME: cache this? distinv = 1.0 / (pplane.dist - mathlib.DotProduct(modelorg, pplane.normal)); surfaces[surface_p].d_zistepu = p_normal[0] * xscaleinv * distinv; surfaces[surface_p].d_zistepv = -p_normal[1] * yscaleinv * distinv; surfaces[surface_p].d_ziorigin = p_normal[2] * distinv - xcenter * surfaces[surface_p].d_zistepu - ycenter * surfaces[surface_p].d_zistepv; //JDC VectorCopy (r_worldmodelorg, surface_p->modelorg); surface_p++; }
/* * ================ * R_RecursiveClipBPoly * ================ */ static void R_RecursiveClipBPoly(bedge_t pedges, model.mnode_t pnode, model.msurface_t psurf) { bedge_t[] psideedges = new bedge_t[2]; bedge_t pnextedge, ptedge; int i, side, lastside; double dist, frac, lastdist; model.mplane_t splitplane, tplane = new model.mplane_t(); model.mvertex_t pvert, plastvert, ptvert; model.node_or_leaf_t pn; psideedges[0] = psideedges[1] = null; makeclippededge = false; // transform the BSP plane into model space // FIXME: cache these? splitplane = pnode.plane; tplane.dist = splitplane.dist - mathlib.DotProduct(r_entorigin, splitplane.normal); tplane.normal[0] = mathlib.DotProduct(entity_rotation[0], splitplane.normal); tplane.normal[1] = mathlib.DotProduct(entity_rotation[1], splitplane.normal); tplane.normal[2] = mathlib.DotProduct(entity_rotation[2], splitplane.normal); // clip edges to BSP plane for ( ; pedges != null; pedges = pnextedge) { pnextedge = pedges.pnext; // set the status for the last point as the previous point // FIXME: cache this stuff somehow? plastvert = pedges.v[0]; lastdist = mathlib.DotProduct(plastvert.position, tplane.normal) - tplane.dist; if (lastdist > 0) { lastside = 0; } else { lastside = 1; } pvert = pedges.v[1]; dist = mathlib.DotProduct(pvert.position, tplane.normal) - tplane.dist; if (dist > 0) { side = 0; } else { side = 1; } if (side != lastside) { // clipped if (numbverts >= MAX_BMODEL_VERTS) { return; } // generate the clipped vertex frac = lastdist / (lastdist - dist); ptvert = pbverts[numbverts++]; ptvert.position[0] = plastvert.position[0] + frac * (pvert.position[0] - plastvert.position[0]); ptvert.position[1] = plastvert.position[1] + frac * (pvert.position[1] - plastvert.position[1]); ptvert.position[2] = plastvert.position[2] + frac * (pvert.position[2] - plastvert.position[2]); // split into two edges, one on each side, and remember entering // and exiting points // FIXME: share the clip edge by having a winding direction flag? if (numbedges >= (MAX_BMODEL_EDGES - 1)) { console.Con_Printf("Out of edges for bmodel\n"); return; } ptedge = pbedges[numbedges]; ptedge.pnext = psideedges[lastside]; psideedges[lastside] = ptedge; ptedge.v[0] = plastvert; ptedge.v[1] = ptvert; ptedge = pbedges[numbedges + 1]; ptedge.pnext = psideedges[side]; psideedges[side] = ptedge; ptedge.v[0] = ptvert; ptedge.v[1] = pvert; numbedges += 2; if (side == 0) { // entering for front, exiting for back pfrontenter = ptvert; makeclippededge = true; } else { pfrontexit = ptvert; makeclippededge = true; } } else { // add the edge to the appropriate side pedges.pnext = psideedges[side]; psideedges[side] = pedges; } } // if anything was clipped, reconstitute and add the edges along the clip // plane to both sides (but in opposite directions) if (makeclippededge) { if (numbedges >= (MAX_BMODEL_EDGES - 2)) { console.Con_Printf("Out of edges for bmodel\n"); return; } ptedge = pbedges[numbedges]; ptedge.pnext = psideedges[0]; psideedges[0] = ptedge; ptedge.v[0] = pfrontexit; ptedge.v[1] = pfrontenter; ptedge = pbedges[numbedges + 1]; ptedge.pnext = psideedges[1]; psideedges[1] = ptedge; ptedge.v[0] = pfrontenter; ptedge.v[1] = pfrontexit; numbedges += 2; } // draw or recurse further for (i = 0; i < 2; i++) { if (psideedges[i] != null) { // draw if we've reached a non-solid leaf, done if all that's left is a // solid leaf, and continue down the tree if it's not a leaf pn = pnode.children[i]; // we're done with this branch if the node or leaf isn't in the PVS if (pn.visframe == r_visframecount) { if (pn.contents < 0) { if (pn.contents != bspfile.CONTENTS_SOLID) { r_currentbkey = ((model.mleaf_t)pn).key; R_RenderBmodelFace(psideedges[i], psurf); } } else { R_RecursiveClipBPoly(psideedges[i], (model.mnode_t)pnode.children[i], psurf); } } } } }
//============================================================================= /* * ================ * D_CacheSurface * ================ */ static surfcache_t D_CacheSurface(model.msurface_t surface, int miplevel) { surfcache_t cache; // // if the surface is animating or flashing, flush the cache // render.r_drawsurf.texture = render.R_TextureAnimation(surface.texinfo.texture); render.r_drawsurf.lightadj[0] = render.d_lightstylevalue[surface.styles[0]]; render.r_drawsurf.lightadj[1] = render.d_lightstylevalue[surface.styles[1]]; render.r_drawsurf.lightadj[2] = render.d_lightstylevalue[surface.styles[2]]; render.r_drawsurf.lightadj[3] = render.d_lightstylevalue[surface.styles[3]]; // // see if the cache holds apropriate data // cache = surface.cachespots[miplevel]; if (cache != null && cache.dlight == 0 && surface.dlightframe != render.r_framecount && cache.texture == render.r_drawsurf.texture && cache.lightadj[0] == render.r_drawsurf.lightadj[0] && cache.lightadj[1] == render.r_drawsurf.lightadj[1] && cache.lightadj[2] == render.r_drawsurf.lightadj[2] && cache.lightadj[3] == render.r_drawsurf.lightadj[3]) { return(cache); } // // determine shape of surface // surfscale = 1.0 / (1 << miplevel); render.r_drawsurf.surfmip = miplevel; render.r_drawsurf.surfwidth = surface.extents[0] >> miplevel; render.r_drawsurf.rowbytes = render.r_drawsurf.surfwidth; render.r_drawsurf.surfheight = surface.extents[1] >> miplevel; // // allocate memory if needed // if (cache == null) // if a texture just animated, don't reallocate it { cache = D_SCAlloc(render.r_drawsurf.surfwidth, render.r_drawsurf.surfwidth * render.r_drawsurf.surfheight); surface.cachespots[miplevel] = cache; cache.owner = surface.cachespots[miplevel]; cache.mipscale = surfscale; } if (surface.dlightframe == render.r_framecount) { cache.dlight = 1; } else { cache.dlight = 0; } render.r_drawsurf.surfdat = cache.data; cache.texture = render.r_drawsurf.texture; cache.lightadj[0] = render.r_drawsurf.lightadj[0]; cache.lightadj[1] = render.r_drawsurf.lightadj[1]; cache.lightadj[2] = render.r_drawsurf.lightadj[2]; cache.lightadj[3] = render.r_drawsurf.lightadj[3]; // // draw and light the surface texture // render.r_drawsurf.surf = surface; render.c_surf++; render.R_DrawSurface(); return(surface.cachespots[miplevel]); }