⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cmodel.pas

📁 雷神之锤2(Quake2)Delphi源码
💻 PAS
📖 第 1 页 / 共 4 页
字号:
    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 + -