📄 r_rast.pas
字号:
R_ClipEdge
================
*)
procedure R_ClipEdge(pv0, pv1: mvertex_p; clip: clipplane_p);
var
d0, d1, f: Single;
clipvert: mvertex_t;
begin
if clip <> nil then
begin
repeat
d0 := DotProduct(pv0^.position, clip^.normal) - clip^.dist;
d1 := DotProduct(pv1^.position, clip^.normal) - clip^.dist;
if d0 >= 0 then
begin
// point 0 is unclipped
if d1 >= 0 then
begin
// both points are unclipped
clip := clip^.next;
continue;
end;
// only point 1 is clipped
// we don't cache clipped edges
cacheoffset := $7FFFFFFF;
f := d0 / (d0 - d1);
clipvert.position[0] := pv0^.position[0] + f * (pv1^.position[0] - pv0^.position[0]);
clipvert.position[1] := pv0^.position[1] + f * (pv1^.position[1] - pv0^.position[1]);
clipvert.position[2] := pv0^.position[2] + f * (pv1^.position[2] - pv0^.position[2]);
if clip^.leftedge <> 0 then
begin
r_leftclipped := true;
r_leftexit := clipvert;
end
else
begin
if clip^.rightedge <> 0 then
begin
r_rightclipped := true;
r_rightexit := clipvert;
end;
end;
R_ClipEdge(pv0, @clipvert, clip^.next);
Exit;
end
else
begin
// point 0 is clipped
if d1 < 0 then
begin
// both points are clipped
// we do cache fully clipped edges
if not r_leftclipped then
begin
cacheoffset := FULLY_CLIPPED_CACHED or (Cardinal(r_framecount) and FRAMECOUNT_MASK);
end;
Exit;
end;
// only point 0 is clipped
r_lastvertvalid := false;
// we don't cache partially clipped edges
cacheoffset := $7FFFFFFF;
f := d0 / (d0 - d1);
clipvert.position[0] := pv0^.position[0] + f * (pv1^.position[0] - pv0^.position[0]);
clipvert.position[1] := pv0^.position[1] + f * (pv1^.position[1] - pv0^.position[1]);
clipvert.position[2] := pv0^.position[2] + f * (pv1^.position[2] - pv0^.position[2]);
if clip^.leftedge <> 0 then
begin
r_leftclipped := true;
r_leftenter := clipvert;
end
else
begin
if clip^.rightedge <> 0 then
begin
r_rightclipped := true;
r_rightenter := clipvert;
end;
end;
R_ClipEdge(@clipvert, pv1, clip^.next);
Exit;
end;
clip := clip^.next;
until clip = nil;
end;
// add the edge
R_EmitEdge(pv0, pv1);
end;
{$ENDIF}
(*
================
R_EmitCachedEdge
================
*)
procedure R_EmitCachedEdge;
var
pedge_t: edge_p;
begin
pedge_t := edge_p(Integer(r_edges) + r_pedge^.cachededgeoffset);
if pedge_t^.surfs[0] = 0 then
pedge_t^.surfs[0] := (Integer(surface_p) - Integer(surfaces)) div sizeof(surf_t)
else
pedge_t^.surfs[1] := (Integer(surface_p) - Integer(surfaces)) div sizeof(surf_t);
if pedge_t^.nearzi > r_nearzi then // for mipmap finding
r_nearzi := pedge_t^.nearzi;
r_emitted := 1;
end;
(*
================
R_RenderFace
================
*)
procedure R_RenderFace(fa: msurface_p; clipflags: Integer);
var
i, lindex: Integer;
mask: Cardinal;
pplane: mplane_p;
distinv: Single;
p_normal: vec3_t;
pedges: medge_p;
tedge: medge_t;
pclip: clipplane_p;
begin
// translucent surfaces are not drawn by the edge renderer
if (fa^.texinfo^.flags and (SURF_TRANS33 or SURF_TRANS66)) <> 0 then
begin
fa^.nextalphasurface := r_alpha_surfaces;
r_alpha_surfaces := fa;
Exit;
end;
// sky surfaces encountered in the world will cause the
// environment box surfaces to be emited
if (fa^.texinfo^.flags and SURF_SKY) <> 0 then
begin
R_EmitSkyBox;
Exit;
end;
// skip out if no more surfs
if Integer(surface_p) >= Integer(surf_max) then
begin
Inc(r_outofsurfaces);
Exit;
end;
// ditto if not enough edges left, or switch to auxedges if possible
if Integer(@PEdge_tArray(edge_p_)^[(fa^.numedges + 4)]) >= Integer(edge_max) then
begin
Inc(r_outofedges, fa^.numedges);
Exit;
end;
Inc(c_faceclip);
// set up clip planes
pclip := nil;
mask := $08;
for i := 3 downto 0 do
begin
if (clipflags and mask) <> 0 then
begin
view_clipplanes[i].next := pclip;
pclip := @view_clipplanes[i];
end;
mask := mask shr 1;
end;
// push the edges through
r_emitted := 0;
r_nearzi := 0;
r_nearzionly := false;
makeleftedge := false;
makerightedge := false;
pedges := currentmodel^.edges;
r_lastvertvalid := false;
for i := 0 to fa^.numedges - 1 do
begin
lindex := PIntegerArray(currentmodel^.surfedges)^[fa^.firstedge + i];
if lindex > 0 then
begin
r_pedge := @medge_arrp(pedges)^[lindex];
// if the edge is cached, we can just reuse the edge
if not insubmodel then
begin
if (r_pedge^.cachededgeoffset and FULLY_CLIPPED_CACHED) <> 0 then
begin
if Integer(r_pedge^.cachededgeoffset and FRAMECOUNT_MASK) = r_framecount then
begin
r_lastvertvalid := false;
continue;
end;
end
else
begin
if (Integer(edge_p_) - Integer(r_edges) > r_pedge^.cachededgeoffset) and
(edge_p(Integer(r_edges) + r_pedge^.cachededgeoffset)^.owner = r_pedge) then
begin
R_EmitCachedEdge;
r_lastvertvalid := false;
continue;
end;
end;
end;
// assume it's cacheable
cacheoffset := Cardinal(edge_p_) - Cardinal(r_edges);
r_leftclipped := false;
r_rightclipped := false;
R_ClipEdge(@mvertex_arrp(r_pcurrentvertbase)^[r_pedge^.v[0]],
@mvertex_arrp(r_pcurrentvertbase)^[r_pedge^.v[1]], pclip);
r_pedge^.cachededgeoffset := cacheoffset;
if r_leftclipped then
makeleftedge := true;
if r_rightclipped then
makerightedge := true;
r_lastvertvalid := true;
end
else
begin
lindex := -lindex;
r_pedge := @medge_arrp(pedges)^[lindex];
// if the edge is cached, we can just reuse the edge
if not insubmodel then
begin
if (r_pedge^.cachededgeoffset and FULLY_CLIPPED_CACHED) > 0 then
begin
if Integer(r_pedge^.cachededgeoffset and FRAMECOUNT_MASK) = r_framecount then
begin
r_lastvertvalid := false;
continue;
end;
end
else
begin
// it's cached if the cached edge is valid and is owned
// by this medge_t
if (Cardinal(edge_p_) - Cardinal(r_edges) > Cardinal(r_pedge^.cachededgeoffset)) and
(edge_p(Integer(r_edges) + r_pedge^.cachededgeoffset)^.owner = r_pedge) then
begin
R_EmitCachedEdge;
r_lastvertvalid := false;
continue;
end;
end;
end;
// assume it's cacheable
cacheoffset := Cardinal(edge_p_) - Cardinal(r_edges);
r_leftclipped := false;
r_rightclipped := false;
R_ClipEdge(@mvertex_arrp(r_pcurrentvertbase)^[r_pedge^.v[1]],
@mvertex_arrp(r_pcurrentvertbase)^[r_pedge^.v[0]], pclip);
r_pedge^.cachededgeoffset := cacheoffset;
if r_leftclipped then
makeleftedge := true;
if r_rightclipped then
makerightedge := true;
r_lastvertvalid := true;
end;
end;
// 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 then
begin
r_pedge := @tedge;
r_lastvertvalid := false;
R_ClipEdge(@r_leftexit, @r_leftenter, pclip^.next);
end;
// if there was a clip off the right edge, get the right r_nearzi
if makerightedge then
begin
r_pedge := @tedge;
r_lastvertvalid := false;
r_nearzionly := true;
R_ClipEdge(@r_rightexit, @r_rightenter, view_clipplanes[1].next);
end;
// if no edges made it out, return without posting the surface
if r_emitted = 0 then
exit;
inc(r_polycount);
surface_p^.msurf := fa;
surface_p^.nearzi := r_nearzi;
surface_p^.flags := fa^.flags;
surface_p^.insubmodel := insubmodel;
surface_p^.spanstate := 0;
surface_p^.entity := currententity;
surface_p^.key := r_currentkey;
inc(r_currentkey);
surface_p^.spans := nil;
pplane := fa^.plane;
// FIXME: cache this?
TransformVector(pplane^.normal, p_normal);
// FIXME: cache this?
distinv := 1.0 / (pplane^.dist - DotProduct(modelorg, pplane^.normal));
surface_p^.d_zistepu := p_normal[0] * xscaleinv * distinv;
surface_p^.d_zistepv := -p_normal[1] * yscaleinv * distinv;
surface_p^.d_ziorigin := p_normal[2] * distinv - xcenter * surface_p^.d_zistepu - ycenter * surface_p^.d_zistepv;
inc(Integer(surface_p), SizeOf(surf_t));
end;
(*
================
R_RenderBmodelFace
================
*)
procedure R_RenderBmodelFace(pedges: bedge_p; psurf: msurface_p);
var
i: Integer;
mask: Cardinal;
pplane: mplane_p;
distinv: Single;
p_normal: vec3_t;
tedge: medge_t;
pclip: clipplane_p;
begin
if (psurf^.texinfo^.flags and (SURF_TRANS33 or SURF_TRANS66)) <> 0 then
begin
psurf^.nextalphasurface := r_alpha_surfaces;
r_alpha_surfaces := psurf;
Exit;
end;
// skip out if no more surfs
if Cardinal(surface_p) >= Cardinal(surf_max) then
begin
inc(r_outofsurfaces);
Exit;
end;
// ditto if not enough edges left, or switch to auxedges if possible
if (Integer(edge_p_) + ((psurf^.numedges + 4) * sizeof(edge_t))) >= Integer(edge_max) then
begin
Inc(r_outofedges, psurf^.numedges);
Exit;
end;
inc(c_faceclip);
// this is a dummy to give the caching mechanism someplace to write to
r_pedge := @tedge;
// set up clip planes
pclip := nil;
mask := $08;
for i := 3 downto 0 do
begin
if (r_clipflags and mask) <> 0 then
begin
view_clipplanes[i].next := pclip;
pclip := @view_clipplanes[i];
end;
mask := mask shr 1;
end;
// push the edges through
r_emitted := 0;
r_nearzi := 0;
r_nearzionly := false;
makeleftedge := false;
makerightedge := false;
// FIXME: keep clipped bmodel edges in clockwise order so last vertex caching
// can be used?
r_lastvertvalid := false;
while (pedges <> nil) do
begin
r_leftclipped := false;
r_rightclipped := false;
R_ClipEdge(pedges^.v[0], pedges^.v[1], pclip);
if (r_leftclipped) then
makeleftedge := true;
if (r_rightclipped) then
makerightedge := true;
pedges := pedges^.pnext;
end;
// 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) then
begin
r_pedge := @tedge;
R_ClipEdge(@r_leftexit, @r_leftenter, pclip^.next);
end;
// if there was a clip off the right edge, get the right r_nearzi
if makerightedge then
begin
r_pedge := @tedge;
r_nearzionly := true;
R_ClipEdge(@r_rightexit, @r_rightenter, view_clipplanes[1].next);
end;
// if no edges made it out, exit without posting the surface
if r_emitted = 0 then
exit;
inc(r_polycount);
surface_p^.msurf := psurf;
surface_p^.nearzi := r_nearzi;
surface_p^.flags := psurf^.flags;
surface_p^.insubmodel := true;
surface_p^.spanstate := 0;
surface_p^.entity := currententity;
surface_p^.key := r_currentbkey;
surface_p^.spans := nil;
pplane := psurf^.plane;
// FIXME: cache this?
TransformVector(pplane^.normal, p_normal);
// FIXME: cache this?
distinv := 1.0 / (pplane^.dist - DotProduct(modelorg, pplane^.normal));
surface_p^.d_zistepu := p_normal[0] * xscaleinv * distinv;
surface_p^.d_zistepv := -p_normal[1] * yscaleinv * distinv;
surface_p^.d_ziorigin := p_normal[2] * distinv - xcenter * surface_p^.d_zistepu - ycenter * surface_p^.d_zistepv;
Inc(Integer(surface_p), SizeOf(surf_t));
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -