📄 gl_rsurf.pas
字号:
{$ALIGN ON}{$MINENUMSIZE 4}
{----------------------------------------------------------------------------}
{ }
{ File(s): GL_RSURF.C: surface-related refresh code }
{ }
{ Initial conversion by : YgriK (Igor Karpov) - glYgriK@hotbox.ru }
{ Initial conversion on : 16-Jan-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. }
{ }
{----------------------------------------------------------------------------}
// 28.06.2003 Juha: Proofreaded
// GL_RSURF.C: surface-related refresh code
unit gl_rsurf;
interface
uses
q_shared,
ref,
qfiles,
gl_local,
OpenGL,
qgl_win,
gl_model_h,
gl_rmain;
procedure R_DrawAlphaSurfaces;
procedure R_DrawBrushModel(e: entity_p);
procedure R_DrawWorld;
procedure R_MarkLeaves;
procedure GL_BuildPolygonFromSurface(fa: msurface_p);
procedure GL_CreateSurfaceLightmap(surf: msurface_p);
procedure GL_BeginBuildingLightmaps(m: model_p);
procedure GL_EndBuildingLightmaps;
var
c_visible_lightmaps: Integer;
c_visible_textures: Integer;
implementation
uses
q_shwin,
SysUtils,
CPas,
DelphiTypes,
qgl_h,
gl_light,
gl_model,
gl_warp,
gl_image;
var
modelorg: vec3_t; // relative to viewpoint
r_alpha_surfaces: msurface_p;
const
DYNAMIC_LIGHT_WIDTH = 128;
DYNAMIC_LIGHT_HEIGHT = 128;
LIGHTMAP_BYTES = 4;
BLOCK_WIDTH = 128;
BLOCK_HEIGHT = 128;
MAX_LIGHTMAPS = 128;
GL_LIGHTMAP_FORMAT = GL_RGBA;
type
gllightmapstate_t = record
internal_format: integer;
current_lightmap_texture: integer;
lightmap_surfaces: array[0..MAX_LIGHTMAPS - 1] of msurface_p;
allocated: array[0..BLOCK_WIDTH - 1] of integer;
// the lightmap texture data needs to be kept in
// main memory so texsubimage can update properly
lightmap_buffer: array[0..4 * BLOCK_WIDTH * BLOCK_HEIGHT - 1] of byte;
end;
var
gl_lms: gllightmapstate_t;
procedure LM_InitBlock; forward;
procedure LM_UploadBlock(dynamic_: qboolean); forward;
function LM_AllocBlock(w, h: integer; var x, y: integer): qboolean; forward;
{*
=============================================================
BRUSH MODELS
=============================================================
*}
{*
===============
R_TextureAnimation
Returns the proper texture for a given time and base texture
===============
*}
function R_TextureAnimation(tex: mtexinfo_p): image_p;
var
c: integer;
begin
if (tex.next = nil) then
begin
Result := tex.image;
Exit;
end;
c := currententity.frame mod tex.numframes;
while (c <> 0) do
begin
tex := tex.next;
Dec(c);
end;
Result := tex.image;
end; //function
(*
/*
=================
WaterWarpPolyVerts
Mangles the x and y coordinates in a copy of the poly
so that any drawing routine can be water warped
=================
*/
glpoly_t *WaterWarpPolyVerts (glpoly_t *p)
{
int i;
float *v, *nv;
static byte buffer[1024];
glpoly_t *out;
out = (glpoly_t * )buffer;
out->numverts = p->numverts;
v = p->verts[0];
nv = out->verts[0];
for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE, nv+=VERTEXSIZE)
{
nv[0] = v[0] + 4*sin(v[1]*0.05+r_newrefdef.time)*sin(v[2]*0.05+r_newrefdef.time);
nv[1] = v[1] + 4*sin(v[0]*0.05+r_newrefdef.time)*sin(v[2]*0.05+r_newrefdef.time);
nv[2] = v[2];
nv[3] = v[3];
nv[4] = v[4];
nv[5] = v[5];
nv[6] = v[6];
}
return out;
}
/*
================
DrawGLWaterPoly
Warp the vertex coordinates
================
*/
void DrawGLWaterPoly (glpoly_t *p)
{
int i;
float *v;
p = WaterWarpPolyVerts (p);
qglBegin (GL_TRIANGLE_FAN);
v = p->verts[0];
for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
{
qglTexCoord2f (v[3], v[4]);
qglVertex3fv (v);
}
qglEnd ();
}
void DrawGLWaterPolyLightmap (glpoly_t *p)
{
int i;
float *v;
p = WaterWarpPolyVerts (p);
qglBegin (GL_TRIANGLE_FAN);
v = p->verts[0];
for (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)
{
qglTexCoord2f (v[5], v[6]);
qglVertex3fv (v);
}
qglEnd ();
}
*)
{*
================
DrawGLPoly
================
*}
procedure DrawGLPoly(p: glpoly_p);
var
i: integer;
v: PSingle;
begin
qglBegin(GL_POLYGON);
i := 0;
v := @p^.verts[0];
while (i < p^.NumVerts) do
begin
qglTexCoord2f(PSingleArray(v)^[3], PSingleArray(v)^[4]);
qglVertex3fv(PGLFloat(v));
Inc(i);
Inc(v, VERTEXSIZE);
end;
qglEnd();
end;
//============
//PGM
{*
================
DrawGLFlowingPoly -- version of DrawGLPoly that handles scrolling texture
================
*}
procedure DrawGLFlowingPoly(fa: msurface_p);
var
i: integer;
v: PSingle;
p: glpoly_p;
scroll: Single;
begin
p := fa.polys;
scroll := -64 * ((r_newrefdef.time / 40.0) - Trunc(r_newrefdef.time / 40.0));
if (scroll = 0.0) then
scroll := -64.0;
qglBegin(GL_POLYGON);
v := @p.verts[0];
i := 0;
while (i < p^.NumVerts) do
begin
qglTexCoord2f((PSingleArray(v)^[3] + scroll), PSingleArray(v)^[4]);
qglVertex3fv(PGLfloat(v));
Inc(v, VERTEXSIZE);
Inc(i);
end;
qglEnd();
end;
//PGM
//============
{*
** R_DrawTriangleOutlines
*}
procedure R_DrawTriangleOutlines;
var
i, j: integer;
p: glpoly_p;
surf: msurface_p;
begin
if (gl_showtris.value = 0) then
Exit;
qglDisable(GL_TEXTURE_2D);
qglDisable(GL_DEPTH_TEST);
qglColor4f(1, 1, 1, 1);
for i := 0 to MAX_LIGHTMAPS - 1 do
begin
surf := gl_lms.lightmap_surfaces[i];
while (surf <> nil) do
begin
p := surf.polys;
while (p <> nil) do
begin
for j := 2 to p.numverts - 1 do
begin
qglBegin(GL_LINE_STRIP);
qglVertex3fv(@p.verts[0]);
qglVertex3fv(@p.verts[j - 1]);
qglVertex3fv(@p.verts[j]);
qglVertex3fv(@p.verts[0]);
qglEnd();
end;
p := p^.chain;
end;
surf := surf^.lightmapchain;
end;
end;
qglEnable(GL_DEPTH_TEST);
qglEnable(GL_TEXTURE_2D);
end; //procedure
{*
** DrawGLPolyChain
*}
procedure DrawGLPolyChain(p: glpoly_p; soffset, toffset: Single);
var
v: PSingle;
j: integer;
begin
if (soffset = 0) and (toffset = 0) then
begin
while (p <> nil) do
begin
qglBegin(GL_POLYGON);
v := @p^.verts[0];
j := 0;
while (j < p^.NumVerts) do
begin
qglTexCoord2f(PSingleArray(v)^[5], PSingleArray(v)^[6]);
qglVertex3fv(PGLfloat(v));
Inc(j);
Inc(v, VERTEXSIZE);
end;
qglEnd();
p := p^.Chain;
end;
end
else
begin
while (p <> nil) do
begin
qglBegin(GL_POLYGON);
v := @p.verts[0];
j := 0;
while (j < p^.NumVerts) do
begin
qglTexCoord2f(PSingleArray(v)^[5] - soffset, PSingleArray(v)^[6] - toffset);
qglVertex3fv(PGLfloat(v));
Inc(j);
Inc(v, VERTEXSIZE);
end;
qglEnd();
p := p^.Chain;
end;
end;
end;
{*
** R_BlendLightMaps
**
** This routine takes all the given light mapped surfaces in the world and
** blends them into the framebuffer.
*}
procedure R_BlendLightmaps;
var
i, smax, tmax: integer;
surf,
newdrawsurf,
drawsurf: msurface_p;
base: PByte;
begin
newdrawsurf := nil;
// don't bother if we're set to fullbright
if (r_fullbright.value <> 0) then
Exit;
if (r_worldmodel.lightdata = nil) then
Exit;
// don't bother writing Z
qglDepthMask(False);
{*
** set the appropriate blending mode unless we're only looking at the
** lightmaps.
*}
if (gl_lightmap.value = 0) then
begin
qglEnable(GL_BLEND);
if (gl_saturatelighting.value <> 0) then
qglBlendFunc(GL_ONE, GL_ONE)
else
begin
if (gl_monolightmap.string_[0] <> '0') then
begin
case UpCase(gl_monolightmap.string_[0]) of
'I': qglBlendFunc(GL_ZERO, GL_SRC_COLOR);
'L': qglBlendFunc(GL_ZERO, GL_SRC_COLOR);
//'A': <- Juha: This falls to default section as well.
else
qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
end;
end
else
qglBlendFunc(GL_ZERO, GL_SRC_COLOR);
end; //else
end; //if
if (currentmodel = r_worldmodel) then
c_visible_lightmaps := 0;
{*
** render static lightmaps first
*}
for i := 1 to MAX_LIGHTMAPS - 1 do
if (gl_lms.lightmap_surfaces[i] <> nil) then
begin
if (currentmodel = r_worldmodel) then
Inc(c_visible_lightmaps);
GL_Bind(gl_state.lightmap_textures + i);
surf := gl_lms.lightmap_surfaces[i];
while (surf <> nil) do
begin
if (surf.polys <> nil) then
DrawGLPolyChain(surf.polys, 0, 0);
surf := surf^.LightMapChain;
end;
end;
{*
** render dynamic lightmaps
*}
if (gl_dynamic.value <> 0) then
begin
LM_InitBlock();
GL_Bind(gl_state.lightmap_textures + 0);
if (currentmodel = r_worldmodel) then
Inc(c_visible_lightmaps);
newdrawsurf := gl_lms.lightmap_surfaces[0];
surf := gl_lms.lightmap_surfaces[0];
while (surf <> nil) do
begin
smax := (surf.extents[0] shr 4) + 1;
tmax := (surf.extents[1] shr 4) + 1;
if (LM_AllocBlock(smax, tmax, surf.dlight_s, surf.dlight_t)) then
begin
base := @gl_lms.lightmap_buffer;
Inc(base, (surf.dlight_t * BLOCK_WIDTH + surf.dlight_s) * LIGHTMAP_BYTES);
R_BuildLightMap(surf, PByteArray(base), BLOCK_WIDTH * LIGHTMAP_BYTES);
end
else
begin
// upload what we have so far
LM_UploadBlock(true);
// draw all surfaces that use this lightmap
drawsurf := newdrawsurf;
while (drawsurf <> surf) do
begin
if (drawsurf.polys <> nil) then
DrawGLPolyChain(drawsurf.polys,
(drawsurf.light_s - drawsurf.dlight_s) * (1.0 / 128.0),
(drawsurf.light_t - drawsurf.dlight_t) * (1.0 / 128.0));
drawsurf := drawsurf^.lightmapchain;
end;
newdrawsurf := drawsurf;
// clear the block
LM_InitBlock();
// try uploading the block now
if (not LM_AllocBlock(smax, tmax, surf.dlight_s, surf.dlight_t)) then
ri.Sys_Error(ERR_FATAL, 'Consecutive calls to LM_AllocBlock(%d,%d) failed (dynamic)'#10, [smax, tmax]);
base := @gl_lms.lightmap_buffer;
Inc(base, (surf.dlight_t * BLOCK_WIDTH + surf.dlight_s) * LIGHTMAP_BYTES);
R_BuildLightMap(surf, PByteArray(base), BLOCK_WIDTH * LIGHTMAP_BYTES);
end;
surf := surf^.lightmapchain;
end;
{*
** draw remainder of dynamic lightmaps that haven't been uploaded yet
*}
if (newdrawsurf <> nil) then
LM_UploadBlock(true);
surf := newdrawsurf;
while (surf <> nil) do
begin
if (surf.polys <> nil) then
DrawGLPolyChain(surf.polys,
(surf.light_s - surf.dlight_s) * (1.0 / 128.0),
(surf.light_t - surf.dlight_t) * (1.0 / 128.0));
surf := surf^.lightmapchain;
end;
end; //if
{*
** restore state
*}
qglDisable(GL_BLEND);
qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
qglDepthMask(True);
end; //procedure
{*
================
R_RenderBrushPoly
================
*}
procedure R_RenderBrushPoly(fa: msurface_p);
var
maps,
smax, tmax: integer;
image: image_p;
is_dynamic: qboolean;
temp: array[0..34 * 34 - 1] of Cardinal;
label
_dynamic;
begin
is_dynamic := false;
Inc(c_brush_polys);
image := R_TextureAnimation(fa.texinfo);
if ((fa.flags and SURF_DRAWTURB) <> 0) then
begin
GL_Bind(image^.texnum);
// warp texture, no lightmaps
GL_TexEnv(GL_MODULATE);
qglColor4f(gl_state.inverse_intensity,
gl_state.inverse_intensity,
gl_state.inverse_intensity,
1.0);
EmitWaterPolys(fa);
GL_TexEnv(GL_REPLACE);
Exit;
end
else
begin
GL_Bind(image^.texnum);
GL_TexEnv(GL_REPLACE);
end;
//======
//PGM
if (fa.texinfo.flags and SURF_FLOWING) <> 0 then
DrawGLFlowingPoly(fa)
else
DrawGLPoly(fa^.polys);
//PGM
//======
{*
** check for lightmap modification
*}
maps := 0;
while (maps < MAXLIGHTMAPS) and (fa^.styles[maps] <> 255) do
begin
if (r_newrefdef.lightstyles[fa^.styles[maps]].white <> fa^.cached_light[maps]) then
goto _dynamic;
Inc(maps);
end;
// dynamic this frame or dynamic previously
if (fa^.dlightframe = r_framecount) then
begin
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -