📄 gl_image.pas
字号:
Fill background pixels so mipmapping doesn't have haloes
=================
*}
type
floodfill_t = record
x, y: SmallInt;
end;
// must be a power of 2
const
FLOODFILL_FIFO_SIZE = $1000;
FLOODFILL_FIFO_MASK = (FLOODFILL_FIFO_SIZE - 1);
procedure R_FloodFillSkin(skin: PByte; skinwidth, skinheight: integer);
var
fillcolor: Byte; // assume this is the pixel to fill
fifo: array[0..FLOODFILL_FIFO_SIZE - 1] of floodfill_t;
inpt, outpt: Integer;
filledcolor: Integer;
x, y, i, fdc: Integer;
pos: PByte;
procedure FLOODFILL_STEP(off, dx, dy: Integer);
begin
if (PByteArray(pos)^[off] = fillcolor) then
begin
PByteArray(pos)[off] := 255;
fifo[inpt].x := x + (dx);
fifo[inpt].y := y + (dy);
inpt := (inpt + 1) and FLOODFILL_FIFO_MASK;
end
else
if (PByteArray(pos)^[off] <> 255) then
fdc := PByteArray(pos)^[off];
end;
begin
fillcolor := skin^; // assume this is the pixel to fill
inpt := 0;
outpt := 0;
filledcolor := -1;
if (filledcolor = -1) then
begin
filledcolor := 0;
// attempt to find opaque black
for i := 1 to 256 - 1 do
if (d_8to24table[i] = (255 shl 0)) then // alpha 1.0
begin
filledcolor := i;
break;
end;
end;
// can't fill to filled color or to transparent color (used as visited marker)
if ((fillcolor = filledcolor) or (fillcolor = 255)) then
begin
//printf( "not filling skin from %d to %d\n", fillcolor, filledcolor );
Exit;
end;
fifo[inpt].x := 0;
fifo[inpt].y := 0;
inpt := (inpt + 1) and FLOODFILL_FIFO_MASK;
while (outpt <> inpt) do
begin
x := fifo[outpt].x;
y := fifo[outpt].y;
fdc := filledcolor;
pos := @PByteArray(skin)^[x + skinwidth * y];
outpt := (outpt + 1) and FLOODFILL_FIFO_MASK;
if (x > 0) then
FLOODFILL_STEP(-1, -1, 0);
if (x < skinwidth - 1) then
FLOODFILL_STEP(1, 1, 0);
if (y > 0) then
FLOODFILL_STEP(-skinwidth, 0, -1);
if (y < skinheight - 1) then
FLOODFILL_STEP(skinwidth, 0, 1);
PByteArray(skin)^[x + skinwidth * y] := fdc;
end;
end;
//=======================================================
{*
================
GL_ResampleTexture
================
*}
procedure GL_ResampleTexture(in_: PCardinal; inwidth, inheight: integer; out_: PCardinal; outwidth, outheight: integer);
var
i, j: Integer;
inrow, inrow2: PCardinal;
frac, fracstep: Cardinal;
p1, p2: array[0..1024 - 1] of Cardinal;
pix1, pix2, pix3, pix4: PByteArray;
tmp: PByteArray; // <- Added by Juha to ease some wicked pointer calculations.
begin
fracstep := (inwidth * $10000) div outwidth;
frac := fracstep shr 2;
for i := 0 to outwidth - 1 do
begin
p1[i] := 4 * (frac shr 16);
frac := frac + fracstep;
end;
frac := 3 * (fracstep shr 2);
for i := 0 to outwidth - 1 do
begin
p2[i] := 4 * (frac shr 16);
frac := frac + fracstep;
end;
for i := 0 to outheight - 1 do
begin
inrow := Pointer(Cardinal(in_) + (inwidth * Trunc((i + 0.25) * inheight / outheight)) * sizeof(Cardinal));
inrow2 := Pointer(Cardinal(in_) + (inwidth * Trunc((i + 0.75) * inheight / outheight)) * sizeof(Cardinal));
frac := fracstep shr 1;
for j := 0 to outwidth - 1 do
begin
pix1 := Pointer(Cardinal(inrow) + p1[j]);
pix2 := Pointer(Cardinal(inrow) + p2[j]);
pix3 := Pointer(Cardinal(inrow2) + p1[j]);
pix4 := Pointer(Cardinal(inrow2) + p2[j]);
tmp := Pointer(Cardinal(out_) + j * sizeof(Cardinal));
tmp[0] := (pix1[0] + pix2[0] + pix3[0] + pix4[0]) shr 2;
tmp[1] := (pix1[1] + pix2[1] + pix3[1] + pix4[1]) shr 2;
tmp[2] := (pix1[2] + pix2[2] + pix3[2] + pix4[2]) shr 2;
tmp[3] := (pix1[3] + pix2[3] + pix3[3] + pix4[3]) shr 2;
end;
Inc(out_, outwidth);
end;
end;
{*
================
GL_LightScaleTexture
Scale up the pixel values in a texture to increase the
lighting range
================
*}
procedure GL_LightScaleTexture(in_: PCardinal; inwidth, inheight: integer; only_gamma: qboolean);
var
i, c: Integer;
p: PByte;
begin
if (only_gamma) then
begin
p := PByte(in_);
c := inwidth * inheight;
for i := 0 to c - 1 do
begin
PByteArray(p)^[0] := gammatable[PByteArray(p)^[0]];
PByteArray(p)^[1] := gammatable[PByteArray(p)^[1]];
PByteArray(p)^[2] := gammatable[PByteArray(p)^[2]];
Inc(p, 4);
end;
end
else
begin
p := PByte(in_);
c := inwidth * inheight;
for i := 0 to c - 1 do
begin
PByteArray(p)^[0] := gammatable[intensitytable[PByteArray(p)^[0]]];
PByteArray(p)^[1] := gammatable[intensitytable[PByteArray(p)^[1]]];
PByteArray(p)^[2] := gammatable[intensitytable[PByteArray(p)^[2]]];
Inc(p, 4);
end;
end;
end;
{*
================
GL_MipMap
Operates in place, quartering the size of the texture
================
*}
procedure GL_MipMap(in_: PByteArray; width, height: integer);
var
i, j: integer;
out_: PByteArray;
begin
width := width shl 2;
height := height shr 1;
out_ := in_;
for i := 0 to height - 1 do
begin
j := 0;
while (j < width) do
begin
out_[0] := (in_[0] + in_[4] + in_[width + 0] + in_[width + 4]) shr 2;
out_[1] := (in_[1] + in_[5] + in_[width + 1] + in_[width + 5]) shr 2;
out_[2] := (in_[2] + in_[6] + in_[width + 2] + in_[width + 6]) shr 2;
out_[3] := (in_[3] + in_[7] + in_[width + 3] + in_[width + 7]) shr 2;
Inc(j, 8);
out_ := Pointer(Cardinal(out_) + 4);
in_ := Pointer(Cardinal(in_) + 8);
end;
in_ := Pointer(Cardinal(in_) + width);
end;
end;
{*
===============
GL_Upload32
Returns has_alpha
===============
*}
procedure GL_BuildPalettedTexture(paletted_texture: PByte; scaled: PByte; scaled_width, scaled_height: integer);
var
i: integer;
r, g, b, c: Cardinal;
begin
for i := 0 to scaled_width * scaled_height - 1 do
begin
r := (PByteArray(scaled)^[0] shr 3) and 31;
g := (PByteArray(scaled)^[1] shr 2) and 63;
b := (PByteArray(scaled)^[2] shr 3) and 31;
c := r or (g shl 5) or (b shl 11);
PByteArray(paletted_texture)[i] := gl_state.d_16to8table[c];
Inc(scaled, 4);
end;
end;
var
upload_width, upload_height: integer;
uploaded_paletted: qboolean;
function GL_Upload32(data: PCardinal; width, height: integer; mipmap: qboolean): qboolean;
var
scaled: array[0..256 * 256 - 1] of Cardinal;
paletted_texture: array[0..256 * 256 - 1] of byte;
samples,
scaled_width, scaled_height,
miplevel: integer;
i, c: Integer;
scan: PByte;
comp: Integer;
label
done;
begin
uploaded_paletted := false;
scaled_width := 1;
while (scaled_width < width) do
scaled_width := scaled_width shl 1;
if (gl_round_down^.value <> 0) and (scaled_width > width) and (mipmap) then
scaled_width := scaled_width shr 1;
scaled_height := 1;
while (scaled_height < height) do
scaled_height := scaled_height shl 1;
if (gl_round_down^.value <> 0) and (scaled_height > height) and (mipmap) then
scaled_height := scaled_height shr 1;
// let people sample down the world textures for speed
if (mipmap) then
begin
scaled_width := scaled_width shr Trunc(gl_picmip^.Value);
scaled_height := scaled_height shr Trunc(gl_picmip^.value);
end;
// don't ever bother with >256 textures
if (scaled_width > 256) then
scaled_width := 256;
if (scaled_height > 256) then
scaled_height := 256;
if (scaled_width < 1) then
scaled_width := 1;
if (scaled_height < 1) then
scaled_height := 1;
upload_width := scaled_width;
upload_height := scaled_height;
if (scaled_width * scaled_height > sizeof(scaled) / 4) then
ri.Sys_Error(ERR_DROP, 'GL_Upload32: too big');
// scan the texture for any non-255 alpha
c := width * height;
scan := Pointer(Cardinal(data) + 3);
samples := gl_solid_format;
for i := 0 to c - 1 do
begin
if (scan^ <> 255) then
begin
samples := gl_alpha_format;
break;
end;
Inc(scan, 4);
end;
if (samples = gl_solid_format) then
comp := gl_tex_solid_format
else
if (samples = gl_alpha_format) then
comp := gl_tex_alpha_format
else
begin
ri.Con_Printf(PRINT_ALL,
'Unknown number of texture components %i'#10,
samples);
comp := samples;
end;
{*
if (mipmap)
gluBuild2DMipmaps (GL_TEXTURE_2D, samples, width, height, GL_RGBA, GL_UNSIGNED_BYTE, trans);
else if (scaled_width == width && scaled_height == height)
qglTexImage2D (GL_TEXTURE_2D, 0, comp, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans);
else
)
gluScaleImage (GL_RGBA, width, height, GL_UNSIGNED_BYTE, trans,
scaled_width, scaled_height, GL_UNSIGNED_BYTE, scaled);
qglTexImage2D (GL_TEXTURE_2D, 0, comp, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);
)
*}
if (scaled_width = width) and (scaled_height = height) then
begin
if (not mipmap) then
begin
if (Assigned(qglColorTableEXT) and (gl_ext_palettedtexture.value <> 0) and (samples = gl_solid_format)) then
begin
uploaded_paletted := true;
GL_BuildPalettedTexture(@paletted_texture, PByte(data), scaled_width, scaled_height);
qglTexImage2D(GL_TEXTURE_2D,
0,
GL_COLOR_INDEX8_EXT,
scaled_width,
scaled_height,
0,
GL_COLOR_INDEX,
GL_UNSIGNED_BYTE,
@paletted_texture);
end
else
qglTexImage2D(GL_TEXTURE_2D, 0, comp, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
goto done;
end;
memcpy(@scaled, data, width * height * 4);
end
else
GL_ResampleTexture(data, width, height, @scaled, scaled_width, scaled_height);
GL_LightScaleTexture(@scaled, scaled_width, scaled_height, not mipmap);
if (Assigned(qglColorTableEXT) and (gl_ext_palettedtexture.Value <> 0) and (samples = gl_solid_format)) then
begin
uploaded_paletted := true;
GL_BuildPalettedTexture(@paletted_texture, @scaled, scaled_width, scaled_height);
qglTexImage2D(GL_TEXTURE_2D,
0,
GL_COLOR_INDEX8_EXT,
scaled_width,
scaled_height,
0,
GL_COLOR_INDEX,
GL_UNSIGNED_BYTE,
@paletted_texture);
end
else
qglTexImage2D(GL_TEXTURE_2D, 0, comp, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, @scaled);
if (mipmap) then
begin
miplevel := 0;
while (scaled_width > 1) or (scaled_height > 1) do
begin
GL_MipMap(@scaled, scaled_width, scaled_height);
scaled_width := scaled_width shr 1;
scaled_height := scaled_height shr 1;
if (scaled_width < 1) then
scaled_width := 1;
if (scaled_height < 1) then
scaled_height := 1;
Inc(miplevel);
if (Assigned(qglColorTableEXT) and (gl_ext_palettedtexture.Value <> 0) and (samples = gl_solid_format)) then
begin
uploaded_paletted := true;
GL_BuildPalettedTexture(@paletted_texture, @scaled, scaled_width, scaled_height);
qglTexImage2D(GL_TEXTURE_2D,
miplevel,
GL_COLOR_INDEX8_EXT,
scaled_width,
scaled_height,
0,
GL_COLOR_INDEX,
GL_UNSIGNED_BYTE,
@paletted_texture);
end
else
qglTexImage2D(GL_TEXTURE_2D, miplevel, comp, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, @scaled);
end;
end;
done: ;
if (mipmap) then
begin
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max)
end
else
begin
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);
qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);
end;
Result := (samples = gl_alpha_format);
end;
{*
===============
GL_Upload8
Returns has_alpha
===============
*}
(*
static qboolean IsPowerOf2( int value )
{
int i = 1;
while ( 1 )
{
if ( value == i )
return true;
if ( i > value )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -