📄 cmodel.pas
字号:
frac := (t1 + offset + DIST_EPSILON)*idist;
end else
begin
side := 0;
frac := 1;
frac2 := 0;
end;
// move up to the node
if (frac < 0) then frac := 0;
if (frac > 1) then frac := 1;
midf := p1f + (p2f - p1f)*frac;
for i:= 0 to 2 do
mid[i] := p1[i] + frac*(p2[i] - p1[i]);
CM_RecursiveHullCheck(node.children[side], p1f, midf, p1, mid);
// go past the node
if (frac2 < 0) then frac2 := 0;
if (frac2 > 1) then frac2 := 1;
midf := p1f + (p2f - p1f)*frac2;
for i:= 0 to 2 do
mid[i] := p1[i] + frac2*(p2[i] - p1[i]);
CM_RecursiveHullCheck(node.children[side xor 1], midf, p2f, mid, p2);
end;
//======================================================================
(*
==================
CM_BoxTrace
==================
*)
function CM_BoxTrace(const start, _end, mins, maxs: vec3_t;
headnode, brushmask: Integer): trace_t;
var
i: Integer;
leafs: array[0..1023] of Integer;
numleafs: Integer;
c1, c2: vec3_t;
topnode: Integer;
begin
Inc(checkcount); // for multi-check avoidance
Inc(c_traces); // for statistics, may be zeroed
// fill in a default trace
FillChar(trace_trace, SizeOf(trace_trace), 0);
trace_trace.fraction := 1;
trace_trace.surface := @nullsurface.c;
if (numnodes = 0) then begin // map not loaded
Result:= trace_trace;
exit;
end;
trace_contents := brushmask;
VectorCopy(start, trace_start);
VectorCopy(_end, trace_end);
VectorCopy(mins, trace_mins);
VectorCopy(maxs, trace_maxs);
//
// check for position test special case
//
if (start[0] = _end[0]) and (start[1] = _end[1]) and (start[2] = _end[2]) then
begin
VectorAdd(start, mins, c1);
VectorAdd(start, maxs, c2);
for i:= 0 to 2 do
begin
c1[i]:= c1[i] - 1;
c2[i]:= c2[i] + 1;
end;
numleafs := CM_BoxLeafnums_headnode(c1, c2, @leafs, 1024, headnode, @topnode);
for i:= 0 to numleafs - 1 do
begin
CM_TestInLeaf(leafs[i]);
if (trace_trace.allsolid) then Break;
end;
VectorCopy(start, trace_trace.endpos);
Result:= trace_trace;
end;
//
// check for point special case
//
if (mins[0] = 0) and (mins[1] = 0) and (mins[2] = 0) and
(maxs[0] = 0) and (maxs[1] = 0) and (maxs[2] = 0) then
begin
trace_ispoint := True;
VectorClear(trace_extents);
end else
begin
trace_ispoint := False;
if (-mins[0] > maxs[0]) then trace_extents[0]:= -mins[0] else trace_extents[0]:= maxs[0];
if (-mins[1] > maxs[1]) then trace_extents[1]:= -mins[1] else trace_extents[1]:= maxs[1];
if (-mins[2] > maxs[2]) then trace_extents[2]:= -mins[2] else trace_extents[2]:= maxs[2];
end;
//
// general sweeping through world
//
CM_RecursiveHullCheck(headnode, 0, 1, start, _end);
if (trace_trace.fraction = 1) then
begin
VectorCopy(_end, trace_trace.endpos);
end else
begin
for i:= 0 to 2 do
trace_trace.endpos[i] := start[i] + trace_trace.fraction * (_end[i] - start[i]);
end;
Result:= trace_trace;
end;
(*
==================
CM_TransformedBoxTrace
Handles offseting and rotation of the end points for moving and
rotating entities
==================
*)
//#ifdef _WIN32
//#pragma optimize( "", off )
//#endif
function CM_TransformedBoxTrace(const start, _end, mins, maxs: vec3_t;
headnode, brushmask: Integer; const origin, angles: vec3_t): trace_t;
var
trace: trace_t;
start_l, end_l: vec3_t;
a: vec3_t;
forward, right, up: vec3_t;
temp: vec3_t;
rotated: qboolean;
begin
// subtract origin offset
VectorSubtract(start, origin, start_l);
VectorSubtract(_end, origin, end_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
rotated := True
else
rotated := False;
if (rotated) then
begin
AngleVectors(angles, @forward, @right, @up);
VectorCopy(start_l, temp);
start_l[0] := DotProduct(temp, forward);
start_l[1] := -DotProduct(temp, right);
start_l[2] := DotProduct(temp, up);
VectorCopy (end_l, temp);
end_l[0] := DotProduct(temp, forward);
end_l[1] := -DotProduct(temp, right);
end_l[2] := DotProduct(temp, up);
end;
// sweep the box through the model
trace := CM_BoxTrace(start_l, end_l, mins, maxs, headnode, brushmask);
if rotated and (trace.fraction <> 1.0) then
begin
// FIXME: figure out how to do this with existing angles
VectorNegate(angles, a);
AngleVectors(a, @forward, @right, @up);
VectorCopy(trace.plane.normal, temp);
trace.plane.normal[0] := DotProduct(temp, forward);
trace.plane.normal[1] := -DotProduct(temp, right);
trace.plane.normal[2] := DotProduct(temp, up);
end;
trace.endpos[0] := start[0] + trace.fraction * (_end[0] - start[0]);
trace.endpos[1] := start[1] + trace.fraction * (_end[1] - start[1]);
trace.endpos[2] := start[2] + trace.fraction * (_end[2] - start[2]);
Result:= trace;
end;
//#ifdef _WIN32
//#pragma optimize( "", on )
//#endif
(*
===============================================================================
PVS / PHS
===============================================================================
*)
(*
===================
CM_DecompressVis
===================
*)
procedure CM_DecompressVis(_in, _out: PByte);
var
c: Integer;
out_p: PByte;
row: Integer;
begin
row := (numclusters+7) shr 3;
out_p := _out;
if (_in = nil) or (numvisibility = 0) then
begin // no vis info, so make all visible
while (row <> 0) do
begin
out_p^ := $ff;
Inc(out_p);
Dec(row);
end;
Exit;
end;
repeat
if (_in^ <> 0) then
begin
out_p^ := _in^; Inc(out_p); Inc(_in);
Continue;
end;
Inc(_in);
c := _in^;
Inc(_in);
if ((Integer(out_p) - Integer(_out)) + c > row) then
begin
c := row - (Integer(out_p) - Integer(_out));
Com_DPrintf('warning: Vis decompression overrun'#10, []);
end;
while (c<>0) do
begin
out_p^ := 0; Inc(out_p);
Dec(c);
end;
until (Integer(out_p) - Integer(_out) >= row);
end;
var
pvsrow: array[0..MAX_MAP_LEAFS div 8 - 1] of Byte;
phsrow: array[0..MAX_MAP_LEAFS div 8 - 1] of Byte;
function CM_ClusterPVS(cluster: Integer): PByte;
begin
if (cluster = -1) then
FillChar(pvsrow, (numclusters+7) shr 3, 0)
else
CM_DecompressVis(@map_visibility[map_vis.bitofs[cluster][DVIS_PVS]], @pvsrow);
Result:= @pvsrow;
end;
function CM_ClusterPHS(cluster: Integer): PByte;
begin
if (cluster = -1) then
FillChar(phsrow, (numclusters+7) shr 3, 0)
else
CM_DecompressVis(@map_visibility[map_vis.bitofs[cluster][DVIS_PHS]], @phsrow);
Result:= @phsrow;
end;
(*
===============================================================================
AREAPORTALS
===============================================================================
*)
procedure FloodArea_r (area: carea_p; floodnum: Integer);
var
i: Integer;
p: dareaportal_p;
begin
if (area.floodvalid = floodvalid) then
begin
if (area.floodnum = floodnum) then Exit;
Com_Error(ERR_DROP, 'FloodArea_r: reflooded', []);
end;
area.floodnum := floodnum;
area.floodvalid := floodvalid;
p := @map_areaportals[area.firstareaportal];
for i:= 0 to area.numareaportals - 1 do // i++, p++)
begin
if (portalopen[p.portalnum]) then
FloodArea_r(@map_areas[p.otherarea], floodnum);
Inc(p);
end;
end;
(*
====================
FloodAreaConnections
====================
*)
procedure FloodAreaConnections;
var
i: Integer;
area: carea_p;
floodnum: Integer;
begin
// all current floods are now invalid
Inc(floodvalid);
floodnum := 0;
// area 0 is not used
for i:= 1 to numareas - 1 do
begin
area := @map_areas[i];
if (area.floodvalid = floodvalid) then Continue; // already flooded into
Inc(floodnum);
FloodArea_r(area, floodnum);
end;
end;
procedure CM_SetAreaPortalState(portalnum: Integer; open: qboolean);
begin
if (portalnum > numareaportals) then
Com_Error(ERR_DROP, 'areaportal > numareaportals', []);
portalopen[portalnum] := open;
FloodAreaConnections;
end;
function CM_AreasConnected(area1, area2: Integer): qboolean;
begin
if (map_noareas.value <> 0) then
begin
Result:= True;
Exit;
end;
if (area1 > numareas) or (area2 > numareas) then
Com_Error(ERR_DROP, 'area > numareas', []);
if (map_areas[area1].floodnum = map_areas[area2].floodnum) then
begin
Result:= True;
Exit;
end;
Result:= False;
end;
(*
=================
CM_WriteAreaBits
Writes a length byte followed by a bit vector of all the areas
that area in the same flood as the area parameter
This is used by the client refreshes to cull visibility
=================
*)
function CM_WriteAreaBits(buffer: PByte; area: Integer): Integer;
var
i: Integer;
floodnum: Integer;
bytes: Integer;
b: PByte;
begin
bytes := (numareas+7) shr 3;
if (map_noareas.value <> 0) then
begin // for debugging, send everything
FillChar(buffer^, bytes, 255);
end else
begin
FillChar(buffer^, bytes, 0);
floodnum := map_areas[area].floodnum;
for i:= 0 to numareas - 1 do
begin
if (map_areas[i].floodnum = floodnum) or (area = 0) then
begin
// buffer[i>>3] |= 1<<(i&7);
b:= @PByteArray(buffer)[i shr 3];
b^:= b^ or (1 shl (i and 7));
end;
end;
end;
Result:= bytes;
end;
(*
===================
CM_WritePortalState
Writes the portal state to a savegame file
===================
*)
procedure CM_WritePortalState(var file_: integer); // (FILE *f);
begin
// fwrite (portalopen, sizeof(portalopen), 1, f);
FileWrite(file_, portalopen, sizeof(portalopen));
end;
(*
===================
CM_ReadPortalState
Reads the portal state from a savegame file
and recalculates the area connections
===================
*)
procedure CM_ReadPortalState(var file_: integer); // (FILE *f);
begin
FS_Read(@portalopen, SizeOf(portalopen), file_);
FloodAreaConnections;
end;
(*
=============
CM_HeadnodeVisible
Returns true if any leaf under headnode has a cluster that
is potentially visible
=============
*)
function CM_HeadnodeVisible(nodenum: Integer; visbits: PByteArray): qboolean;
var
leafnum: Integer;
cluster: Integer;
node: cnode_p;
begin
if (nodenum < 0) then
begin
leafnum := -1-nodenum;
cluster := map_leafs[leafnum].cluster;
if (cluster = -1) then
begin
Result:= False;
Exit;
end;
// if (visbits[cluster>>3] & (1<<(cluster&7)))
if (PByteArray(visbits)[cluster shr 3] and (1 shl (cluster and 7))) <> 0 then
begin
Result:= True;
Exit;
end;
Result:= false;
Exit;
end;
node := @map_nodes[nodenum];
if CM_HeadnodeVisible(node.children[0], visbits) then
begin
Result:= true;
Exit;
end;
Result:= CM_HeadnodeVisible(node.children[1], visbits);
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -