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

📄 cmodel.pas

📁 delphi编的不错的贪吃蛇
💻 PAS
📖 第 1 页 / 共 4 页
字号:
    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
==================
*)

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;

(*
===============================================================================

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);
begin
  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);
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 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 + -