📄 cmodel.pas
字号:
end;
function CM_PointLeafnum(p: vec3_p): Integer;
begin
if (numplanes = 0) then
Result:= 0 // sound may call this without map loaded
else
Result:= CM_PointLeafnum_r(p^, 0);
end;
(*
=============
CM_BoxLeafnums
Fills in a list of all the leafs touched
=============
*)
{$IFNDEF COMPILER6_UP}
type
IntegerArray = array[0..$effffff] of Integer;
PIntegerArray = ^IntegerArray;
{$ENDIF}
var
leaf_count, leaf_maxcount: Integer;
leaf_list: PIntegerArray;
leaf_mins, leaf_maxs: vec3_p;
leaf_topnode: Integer;
procedure CM_BoxLeafnums_r(nodenum: Integer);
var
plane: cplane_p;
node: cnode_p;
s: Integer;
begin
while True do
begin
if (nodenum < 0) then
begin
if (leaf_count >= leaf_maxcount) then
begin
// Com_Printf ('CM_BoxLeafnums_r: overflow'#10);
Exit;
end;
leaf_list[leaf_count] := -1 - nodenum;
Inc(leaf_count);
Exit;
end;
node := @map_nodes[nodenum];
plane := node.plane;
// s = BoxOnPlaneSide (leaf_mins, leaf_maxs, plane);
s := BOX_ON_PLANE_SIDE(leaf_mins^, leaf_maxs^, plane);
if (s = 1) then
nodenum := node.children[0]
else if (s = 2) then
nodenum := node.children[1]
else
begin // go down both
if (leaf_topnode = -1) then
leaf_topnode := nodenum;
CM_BoxLeafnums_r(node.children[0]);
nodenum := node.children[1];
end;
end;
end;
function CM_BoxLeafnums_headnode(var mins, maxs: vec3_t;
list: PIntegerArray; listsize, headnode: Integer; topnode: PInteger): Integer;
begin
leaf_list := list;
leaf_count := 0;
leaf_maxcount := listsize;
leaf_mins := @mins;
leaf_maxs := @maxs;
leaf_topnode := -1;
CM_BoxLeafnums_r(headnode);
if (topnode <> nil) then
topnode^ := leaf_topnode;
Result:= leaf_count;
end;
function CM_BoxLeafnums(var mins, maxs: vec3_t; list: PInteger;
listsize: Integer; topnode: PInteger): Integer;
begin
Result:= CM_BoxLeafnums_headnode(mins, maxs, PIntegerArray(list), listsize,
map_cmodels[0].headnode, topnode);
end;
(*
==================
CM_PointContents
==================
*)
function CM_PointContents(const p: vec3_t; headnode: Integer): Integer;
var
l: Integer;
begin
if (numnodes = 0) then // map not loaded
begin
Result:= 0;
Exit;
end;
l := CM_PointLeafnum_r(p, headnode);
Result:= map_leafs[l].contents;
end;
(*
==================
CM_TransformedPointContents
Handles offseting and rotation of the end points for moving and
rotating entities
==================
*)
function CM_TransformedPointContents(const p: vec3_t; headnode: Integer;
const origin, angles: vec3_t): Integer;
var
p_l: vec3_t;
temp: vec3_t;
forward, right, up: vec3_t;
l: Integer;
begin
// subtract origin offset
VectorSubtract(p, origin, p_l);
// rotate start and end into the models frame of reference
if (headnode <> box_headnode) and
((angles[0]<>0) or (angles[1]<>0) or (angles[2]<>0)) then
begin
AngleVectors(angles, @forward, @right, @up);
VectorCopy(p_l, temp);
p_l[0] := DotProduct(temp, forward);
p_l[1] := -DotProduct(temp, right);
p_l[2] := DotProduct(temp, up);
end;
l := CM_PointLeafnum_r(p_l, headnode);
Result:= map_leafs[l].contents;
end;
(*
===============================================================================
BOX TRACING
===============================================================================
*)
// 1/32 epsilon to keep floating point happy
const
DIST_EPSILON: Single = (0.03125);
var
trace_start, trace_end: vec3_t;
trace_mins, trace_maxs: vec3_t;
trace_extents: vec3_t;
trace_trace: trace_t;
trace_contents: Integer;
trace_ispoint: qboolean; // optimized case
(*
================
CM_ClipBoxToBrush
================
*)
procedure CM_ClipBoxToBrush(mins, maxs, p1, p2: vec3_t;
trace: trace_p; brush: cbrush_p);
var
i, j: Integer;
plane, clipplane: cplane_p;
dist: Single;
enterfrac, leavefrac: Single;
ofs: vec3_t;
d1, d2: Single;
getout, startout: qboolean;
f: Single;
side, leadside: cbrushside_p;
begin
enterfrac := -1;
leavefrac := 1;
clipplane := nil;
if (brush.numsides = 0) then Exit;
Inc(c_brush_traces);
getout := False;
startout := False;
leadside := nil;
for i:= 0 to brush.numsides - 1 do
begin
side := @map_brushsides[brush.firstbrushside+i];
plane := side.plane;
// FIXME: special case for axial
if trace_ispoint then
begin // general box case
// push the plane out apropriately for mins/maxs
// FIXME: use signbits into 8 way lookup for each mins/maxs
for j:= 0 to 2 do
begin
if (plane.normal[j] < 0) then
ofs[j] := maxs[j]
else
ofs[j] := mins[j];
end;
dist := DotProduct(ofs, plane.normal);
dist := plane.dist - dist;
end else
begin // special point case
dist := plane.dist;
end;
d1 := DotProduct(p1, plane.normal) - dist;
d2 := DotProduct(p2, plane.normal) - dist;
if (d2 > 0) then
getout := True; // endpoint is not in solid
if (d1 > 0) then
startout := True;
// if completely in front of face, no intersection
if (d1 > 0) and (d2 >= d1) then Exit;
if (d1 <= 0) and (d2 <= 0) then Continue;
// crosses face
if (d1 > d2) then
begin // enter
f := (d1-DIST_EPSILON) / (d1-d2);
if (f > enterfrac) then
begin
enterfrac := f;
clipplane := plane;
leadside := side;
end;
end else
begin // leave
f := (d1+DIST_EPSILON) / (d1-d2);
if (f < leavefrac) then
leavefrac := f;
end;
end;
if startout then
begin // original point was inside brush
trace.startsolid := true;
if getout then
trace.allsolid := True;
Exit;
end;
if (enterfrac < leavefrac) then
begin
if (enterfrac > -1) and (enterfrac < trace.fraction) then
begin
if (enterfrac < 0) then
enterfrac := 0;
trace.fraction := enterfrac;
trace.plane := clipplane^;
trace.surface := @leadside.surface.c;
trace.contents := brush.contents;
end;
end;
end;
(*
================
CM_TestBoxInBrush
================
*)
procedure CM_TestBoxInBrush(const mins, maxs, p1: vec3_t;
var trace: trace_t; brush: cbrush_p);
var
i, j: Integer;
plane: cplane_p;
dist: Single;
ofs: vec3_t;
d1: Single;
side: cbrushside_p;
begin
if (brush.numsides = 0) then Exit;
for i:= 0 to brush.numsides - 1 do
begin
side := @map_brushsides[brush.firstbrushside+i];
plane := side.plane;
// FIXME: special case for axial
// general box case
// push the plane out apropriately for mins/maxs
// FIXME: use signbits into 8 way lookup for each mins/maxs
for j:= 0 to 2 do
begin
if (plane.normal[j] < 0) then
ofs[j] := maxs[j]
else
ofs[j] := mins[j];
end;
dist := DotProduct(ofs, plane.normal);
dist := plane.dist - dist;
d1 := DotProduct(p1, plane.normal) - dist;
// if completely in front of face, no intersection
if (d1 > 0) then Exit;
end;
// inside this brush
trace.allsolid := True;
trace.startsolid := True;
trace.fraction := 0;
trace.contents := brush.contents;
end;
(*
================
CM_TraceToLeaf
================
*)
procedure CM_TraceToLeaf(leafnum: Integer);
var
k: Integer;
brushnum: Integer;
leaf: cleaf_p;
b: cbrush_p;
begin
leaf := @map_leafs[leafnum];
if ((leaf.contents and trace_contents) = 0) then Exit;
// trace line against all brushes in the leaf
for k:= 0 to leaf.numleafbrushes -1 do
begin
brushnum := map_leafbrushes[leaf.firstleafbrush+k];
b := @map_brushes[brushnum];
if (b.checkcount = checkcount) then
Continue; // already checked this brush in another leaf
b.checkcount := checkcount;
if ((b.contents and trace_contents) = 0) then
Continue;
CM_ClipBoxToBrush(trace_mins, trace_maxs, trace_start, trace_end, @trace_trace, b);
if (trace_trace.fraction = 0) then Exit;
end;
end;
(*
================
CM_TestInLeaf
================
*)
procedure CM_TestInLeaf(leafnum: Integer);
var
k: Integer;
brushnum: Integer;
leaf: cleaf_p;
b: cbrush_p;
begin
leaf := @map_leafs[leafnum];
if ((leaf.contents and trace_contents) = 0) then Exit;
// trace line against all brushes in the leaf
for k:= 0 to leaf.numleafbrushes - 1 do
begin
brushnum := map_leafbrushes[leaf.firstleafbrush+k];
b := @map_brushes[brushnum];
if (b.checkcount = checkcount) then
Continue; // already checked this brush in another leaf
b.checkcount := checkcount;
if ((b.contents and trace_contents) = 0) then
Continue;
CM_TestBoxInBrush(trace_mins, trace_maxs, trace_start, trace_trace, b);
if (trace_trace.fraction = 0) then Exit;
end;
end;
(*
==================
CM_RecursiveHullCheck
==================
*)
procedure CM_RecursiveHullCheck(num: Integer; p1f, p2f: Single; const p1, p2: vec3_t);
var
node: cnode_p;
plane: cplane_p;
t1, t2, offset: Single;
frac, frac2: Single;
idist: Single;
i: Integer;
mid: vec3_t;
side: Integer;
midf: Single;
begin
if (trace_trace.fraction <= p1f) then Exit; // already hit something nearer
// if < 0, we are in a leaf node
if (num < 0) then
begin
CM_TraceToLeaf(-1-num);
Exit;
end;
//
// find the point distances to the seperating plane
// and the offset for the size of the box
//
node := @map_nodes[num];
plane := node.plane;
if (plane._type < 3) then
begin
t1 := p1[plane._type] - plane.dist;
t2 := p2[plane._type] - plane.dist;
offset := trace_extents[plane._type];
end else
begin
t1 := DotProduct(plane.normal, p1) - plane.dist;
t2 := DotProduct(plane.normal, p2) - plane.dist;
if (trace_ispoint) then
offset := 0
else
offset :=
fabs(trace_extents[0]*plane.normal[0]) +
fabs(trace_extents[1]*plane.normal[1]) +
fabs(trace_extents[2]*plane.normal[2]);
end;
{$Undef False}
{$ifdef False}
//#if 0
CM_RecursiveHullCheck (node->children[0], p1f, p2f, p1, p2);
CM_RecursiveHullCheck (node->children[1], p1f, p2f, p1, p2);
return;
{$endif}
// see which sides we need to consider
if (t1 >= offset) and (t2 >= offset) then
begin
CM_RecursiveHullCheck(node.children[0], p1f, p2f, p1, p2);
Exit;
end;
if (t1 < -offset) and (t2 < -offset) then
begin
CM_RecursiveHullCheck(node.children[1], p1f, p2f, p1, p2);
Exit;
end;
// put the crosspoint DIST_EPSILON pixels on the near side
if (t1 < t2) then
begin
idist := 1.0/(t1-t2);
side := 1;
frac2 := (t1 + offset + DIST_EPSILON)*idist;
frac := (t1 - offset + DIST_EPSILON)*idist;
end else if (t1 > t2) then
begin
idist := 1.0/(t1-t2);
side := 0;
frac2 := (t1 - offset - DIST_EPSILON)*idist;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -