📄 r_rast.pas
字号:
//100%
{$ALIGN 8}{$MINENUMSIZE 4}
{----------------------------------------------------------------------------}
{ }
{ File(s): r_rast.c }
{ Content: }
{ }
{ Initial conversion by : Carl A Kenner (carl_kenner@hotmail.com) }
{ Initial conversion on : 23-Feb-2002 }
{ }
{ This File contains part of convertion of Quake2 source to ObjectPascal. }
{ More information about this project can be found at: }
{ http://www.sulaco.co.za/quake2/ }
{ }
{ Copyright (C) 1997-2001 Id Software, Inc. }
{ }
{ This program is free software; you can redistribute it and/or }
{ modify it under the terms of the GNU General Public License }
{ as published by the Free Software Foundation; either version 2 }
{ of the License, or (at your option) any later version. }
{ }
{ This program is distributed in the hope that it will be useful, }
{ but WITHOUT ANY WARRANTY; without even the implied warranty of }
{ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. }
{ }
{ See the GNU General Public License for more details. }
{ }
{----------------------------------------------------------------------------}
{ Updated on : 25-Feb-2002 }
{ Updated by : Carl A Kenner (carl_kenner@hotmail.com) }
{ Updated on : 12-Aug-2002 }
{ Updated by : CodeFusion (Michael@skovslund.dk) }
{ }
{----------------------------------------------------------------------------}
{ * Still dependent (to compile correctly) on: }
{ none }
{----------------------------------------------------------------------------}
{ * TODO: }
{----------------------------------------------------------------------------}
// r_rast.c
unit r_rast;
{$DEFINE _NODEPEND}
interface
uses
q_shared,
qfiles,
r_model,
r_misc,
r_local;
procedure R_InitSkyBox;
procedure R_RenderFace(fa: msurface_p; clipflags: Integer);
procedure R_EmitEdge(pv0, pv1: mvertex_p);
procedure R_RenderBmodelFace(pedges: bedge_p; psurf: msurface_p);
var
sintable: array[0..1279] of Integer;
intsintable: array[0..1279] of Integer;
blanktable: array[0..1279] of Integer; // PGM
view_clipplanes: array[0..3] of clipplane_t;
c_faceclip: Integer; // number of faces clipped
r_skytexinfo: array[0..5] of mtexinfo_t;
implementation
uses
r_poly,
r_edgea,
r_edge,
r_bsp_c,
r_main,
SysUtils;
const
MAXLEFTCLIPEDGES = 100;
// !!! if these are changed, they must be changed in asm_draw.h too !!!
FULLY_CLIPPED_CACHED = $80000000;
FRAMECOUNT_MASK = $7FFFFFFF;
var
cacheoffset: Cardinal;
// entity_clipplanes : clipplane_p;
// world_clipplanes : Array[0..15] of clipplane_t;
r_pedge: medge_p;
r_leftclipped: qboolean;
r_rightclipped: qboolean;
r_nearzionly: qboolean;
r_leftenter: mvertex_t;
r_leftexit: mvertex_t;
r_rightenter: mvertex_t;
r_rightexit: mvertex_t;
type
evert_p = ^evert_t;
pevert_t = evert_p;
evert_t = record
u, v: Single;
ceilv: Integer;
end;
TEvert = evert_t;
PEvert = evert_p;
var
r_emitted: Integer;
r_nearzi: Single;
r_u1, r_v1, r_lzi1: Single;
r_ceilv1: Integer;
r_lastvertvalid: qboolean;
r_skyframe: Integer;
r_skyfaces: msurface_p;
r_skyplanes: array[0..5] of mplane_t;
r_skyverts: mvertex_p;
r_skyedges: medge_p;
r_skysurfedges: PInteger;
// I just copied this data from a box map...
var
skybox_planes: array[0..11] of Integer = (2, -128, 0, -128, 2, 128, 1, 128, 0, 128, 1, -128);
box_surfedges: array[0..23] of Integer = (1, 2, 3, 4, -1, 5, 6, 7, 8, 9, -6, 10, -2, -7, -9, 11,
12, -3, -11, -8, -12, -10, -5, -4);
box_edges: array[0..23] of Integer = (1, 2, 2, 3, 3, 4, 4, 1, 1, 5, 5, 6, 6, 2,
7, 8, 8, 6, 5, 7, 8, 3, 7, 4);
box_faces: array[0..5] of Integer = (0, 0, 2, 2, 2, 0);
box_vecs: array[0..5, 0..1] of vec3_t = (
((0, -1, 0), (-1, 0, 0)),
((0, 1, 0), (0, 0, -1)),
((0, -1, 0), (1, 0, 0)),
((1, 0, 0), (0, 0, -1)),
((0, -1, 0), (0, 0, -1)),
((-1, 0, 0), (0, 0, -1))
);
box_verts: array[0..7, 0..2] of Single = (
(-1, -1, -1),
(-1, 1, -1),
(1, 1, -1),
(1, -1, -1),
(-1, -1, 1),
(-1, 1, 1),
(1, -1, 1),
(1, 1, 1)
);
// down, west, up, north, east, south
// {"rt", "bk", "lf", "ft", "up", "dn"};
var
makeleftedge,
makerightedge: qboolean; // CAK - global static means other units can't use it
(*
================
R_InitSkyBox
================
*)
procedure R_InitSkyBox;
var
i: Integer;
begin
// r_skyfaces := msurface_p(Integer(loadmodel^.surfaces)+(loadmodel^.numsurfaces*SizeOf(msurface_t)));
r_skyfaces := @msurface_arrp(loadmodel^.surfaces)^[loadmodel^.numsurfaces];
Inc(loadmodel^.numsurfaces, 6);
// r_skyverts := mvertex_p(Integer(loadmodel^.vertexes)+(loadmodel^.numvertexes*SizeOf(mvertex_t)));
r_skyverts := @mvertex_arrp(loadmodel^.vertexes)^[loadmodel^.numvertexes];
Inc(loadmodel^.numvertexes, 8);
// r_skyedges := medge_p(Integer(loadmodel^.edges)+(loadmodel^.numedges*SizeOf(medge_t)));
r_skyedges := @medge_arrp(loadmodel^.edges)^[loadmodel^.numedges];
Inc(loadmodel^.numedges, 12);
// r_skysurfedges := PInteger(Integer(loadmodel^.surfedges)+(loadmodel^.numsurfedges*SizeOf(Integer)));
r_skysurfedges := @PIntegerArray(loadmodel^.surfedges)^[loadmodel^.numsurfedges];
Inc(loadmodel^.numsurfedges, 24);
if (loadmodel^.numsurfaces > MAX_MAP_FACES) or (loadmodel^.numvertexes > MAX_MAP_VERTS) or (loadmodel^.numedges > MAX_MAP_EDGES) then
ri.Sys_Error(ERR_DROP, 'InitSkyBox: map overflow');
FillChar(r_skyfaces^, 6*sizeof(r_skyfaces^), 0);
for i:= 0 to 5 do
begin
r_skyplanes[i].normal[skybox_planes[i * 2]] := 1;
r_skyplanes[i].dist := skybox_planes[i * 2 + 1];
VectorCopy(box_vecs[i][0], vec3_p(@r_skytexinfo[i].vecs[0][0])^);
VectorCopy(box_vecs[i][1], vec3_p(@r_skytexinfo[i].vecs[1][0])^);
msurface_arrp(r_skyfaces)^[i].plane := @r_skyplanes[i];
msurface_arrp(r_skyfaces)^[i].numedges := 4;
msurface_arrp(r_skyfaces)^[i].flags := box_faces[i] or SURF_DRAWSKYBOX;
msurface_arrp(r_skyfaces)^[i].firstedge := loadmodel.numsurfedges - 24 + i * 4;
msurface_arrp(r_skyfaces)^[i].texinfo := @r_skytexinfo[i];
msurface_arrp(r_skyfaces)^[i].texturemins[0] := -128;
msurface_arrp(r_skyfaces)^[i].texturemins[1] := -128;
msurface_arrp(r_skyfaces)^[i].extents[0] := 256;
msurface_arrp(r_skyfaces)^[i].extents[1] := 256;
end;
for i := 0 to 23 do
begin
if box_surfedges[i] > 0 then
PIntegerArray(r_skysurfedges)^[i] := loadmodel^.numedges - 13 + box_surfedges[i]
// PInteger(Integer(r_skysurfedges)+(i*SizeOf(Integer)))^ := loadmodel.numedges-13 + box_surfedges[i]
else
PIntegerArray(r_skysurfedges)^[i] := -(loadmodel^.numedges-13 + (-box_surfedges[i]));
// PInteger(Integer(r_skysurfedges)+(i*SizeOf(Integer)))^ := - (loadmodel.numedges-13 + -box_surfedges[i]);
end;
for i := 0 to 11 do
begin
medge_arrp(r_skyedges)^[i].v[0] := loadmodel.numvertexes - 9 + box_edges[i * 2 + 0];
medge_arrp(r_skyedges)^[i].v[1] := loadmodel.numvertexes - 9 + box_edges[i * 2 + 1];
medge_arrp(r_skyedges)^[i].cachededgeoffset := 0;
end;
end;
(*
================
R_EmitSkyBox
================
*)
procedure R_EmitSkyBox;
var
i, j: Integer;
oldkey: Integer;
begin
if insubmodel then
exit; // submodels should never have skies
if r_skyframe = r_framecount then
exit; // already set this frame
r_skyframe := r_framecount;
// set the eight fake vertexes
for i := 0 to 7 do
for j := 0 to 2 do
mvertex_arrp(r_skyverts)^[i].position[j] := r_origin[j] + box_verts[i][j] * 128;
// set the six fake planes
for i := 0 to 5 do
if skybox_planes[(i * 2) + 1] > 0 then
r_skyplanes[i].dist := r_origin[skybox_planes[i * 2]] + 128
else
r_skyplanes[i].dist := r_origin[skybox_planes[i * 2]] - 128;
// fix texture offseets
for i := 0 to 5 do
begin
r_skytexinfo[i].vecs[0][3] := -DotProduct(r_origin, vec3_p(@r_skytexinfo[i].vecs[0][0])^);
r_skytexinfo[i].vecs[1][3] := -DotProduct(r_origin, vec3_p(@r_skytexinfo[i].vecs[1][0])^);
end;
// emit the six faces
oldkey := r_currentkey;
r_currentkey := $7FFFFFF0;
for i := 0 to 5 do
begin
R_RenderFace(@msurface_arrp(r_skyfaces)^[i], 15);
end;
r_currentkey := oldkey; // bsp sorting order
end;
(*
================
R_EmitEdge
================
*)
{$IFNDEF id386}
procedure R_EmitEdge(pv0, pv1: mvertex_p);
var
edge, pcheck: edge_p;
u_check: Integer;
u, u_step: Single;
local: vec3_t;
transformed: vec3_t;
world: PSingle;
v, v2, ceilv0: Integer;
scale, lzi0: Single;
u0, v0: Single;
side: Integer;
begin
if r_lastvertvalid then
begin
u0 := r_u1;
v0 := r_v1;
lzi0 := r_lzi1;
ceilv0 := r_ceilv1;
end
else
begin
world := @pv0^.position[0];
// transform and project
VectorSubtract(vec3_p(world)^, modelorg, local);
TransformVector(local, transformed);
if transformed[2] < NEAR_CLIP then
transformed[2] := NEAR_CLIP;
lzi0 := 1.0 / transformed[2];
// FIXME: build x/yscale into transform?
scale := xscale * lzi0;
u0 := xcenter + scale * transformed[0];
if u0 < r_refdef.fvrectx_adj then
u0 := r_refdef.fvrectx_adj;
if u0 > r_refdef.fvrectright_adj then
u0 := r_refdef.fvrectright_adj;
scale := yscale * lzi0;
v0 := ycenter - scale * transformed[1];
if v0 < r_refdef.fvrecty_adj then
v0 := r_refdef.fvrecty_adj;
if v0 > r_refdef.fvrectbottom_adj then
v0 := r_refdef.fvrectbottom_adj;
ceilv0 := ceil(v0);
end;
world := @pv1^.position[0];
// transform and project
VectorSubtract(vec3_p(world)^, modelorg, local);
TransformVector(local, transformed);
if transformed[2] < NEAR_CLIP then
transformed[2] := NEAR_CLIP;
r_lzi1 := 1.0 / transformed[2];
scale := xscale * r_lzi1;
r_u1 := (xcenter + scale * transformed[0]);
if r_u1 < r_refdef.fvrectx_adj then
r_u1 := r_refdef.fvrectx_adj;
if r_u1 > r_refdef.fvrectright_adj then
r_u1 := r_refdef.fvrectright_adj;
scale := yscale * r_lzi1;
r_v1 := ycenter - scale * transformed[1];
if r_v1 < r_refdef.fvrecty_adj then
r_v1 := r_refdef.fvrecty_adj;
if r_v1 > r_refdef.fvrectbottom_adj then
r_v1 := r_refdef.fvrectbottom_adj;
if r_lzi1 > lzi0 then
lzi0 := r_lzi1;
if lzi0 > r_nearzi then // for mipmap finding
r_nearzi := lzi0;
// for right edges, all we want is the effect on 1/z
if r_nearzionly then
exit;
r_emitted := 1;
r_ceilv1 := ceil(r_v1);
// create the edge
if ceilv0 = r_ceilv1 then
begin
// we cache unclipped horizontal edges as fully clipped
if cacheoffset <> $7FFFFFFF then
begin
cacheoffset := FULLY_CLIPPED_CACHED or (Cardinal(r_framecount) and FRAMECOUNT_MASK);
end;
exit; // horizontal edge
end;
side := Integer(ceilv0 > r_ceilv1);
edge := edge_p_;
Inc(Integer(edge_p_), SizeOf(edge_p_^));
edge^.owner := r_pedge;
edge^.nearzi := lzi0;
if side = 0 then
begin
// trailing edge (go from p1 to p2)
v := ceilv0;
v2 := r_ceilv1 - 1;
edge^.surfs[0] := (Integer(surface_p) - Integer(surfaces)) div sizeof(surf_t);
edge^.surfs[1] := 0;
u_step := ((r_u1 - u0) / (r_v1 - v0));
u := v;
u := u0 + (u - v0) * u_step;
end
else
begin
// leading edge (go from p2 to p1)
v2 := ceilv0 - 1;
v := r_ceilv1;
edge^.surfs[0] := 0;
edge^.surfs[1] := (Integer(surface_p) - Integer(surfaces)) div sizeof(surf_t);
u_step := ((u0 - r_u1) / (v0 - r_v1));
u := v;
u := r_u1 + (u - r_v1) * u_step;
end;
edge^.u_step := Trunc(u_step * $100000); // CAK truncate or round ???? CODEFUSION -> Trunc!!!!
edge^.u := Trunc(u * $100000 + $FFFFF);
// we need to do this to avoid stepping off the edges if a very nearly
// horizontal edge is less than epsilon above a scan, and numeric error causes
// it to incorrectly extend to the scan, and the extension of the line goes off
// the edge of the screen
// FIXME: is this actually needed?
if edge^.u < r_refdef.vrect_x_adj_shift20 then
edge^.u := r_refdef.vrect_x_adj_shift20;
if edge^.u > r_refdef.vrectright_adj_shift20 then
edge^.u := r_refdef.vrectright_adj_shift20;
//
// sort the edge in normally
//
u_check := edge^.u;
if edge^.surfs[0] <> 0 then
inc(u_check); // sort trailers after leaders
if (newedges[v] = nil) or (newedges[v]^.u >= u_check) then
begin
edge^.next := newedges[v];
newedges[v] := edge;
end
else
begin
pcheck := newedges[v];
while (pcheck^.next <> nil) and (pcheck^.next^.u < u_check) do
pcheck := pcheck^.next;
edge^.next := pcheck^.next;
pcheck^.next := edge;
end;
edge^.nextremove := removeedges[v2];
removeedges[v2] := edge;
end;
(*
================
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -