📄 r_part.pas
字号:
// EDI = pdest = d_viewbuffer + d_scantable[v] + u;
lea edi, [d_scantable+ecx*4]
mov edi, [edi]
add edi, d_viewbuffer
add edi, ebx
// complete
// izi = (int)(zi * 0x8000);
fistp tmp
mov eax, tmp
mov izi, ax
{
** determine the screen area covered by the particle,
** which also means clamping to a min and max
}
// pix = izi >> d_pix_shift;
xor edx, edx
mov dx, izi
mov ecx, d_pix_shift
shr dx, cl
// if (pix < d_pix_min)
// pix = d_pix_min;
cmp edx, d_pix_min
jge check_pix_max
mov edx, d_pix_min
jmp skip_pix_clamp
// else if (pix > d_pix_max)
// pix = d_pix_max;
check_pix_max:
cmp edx, d_pix_max
jle skip_pix_clamp
mov edx, d_pix_max
skip_pix_clamp:
{
** render the appropriate pixels
**
** ECX = count (used for inner loop)
** EDX = count (used for outer loop)
** ESI = zbuffer
** EDI = framebuffer
}
mov ecx, edx
cmp ecx, 1
ja over
over:
{
** at this point:
**
** ECX = count
}
push ecx
push edi
push esi
top_of_pix_vert_loop:
top_of_pix_horiz_loop:
// for ( ; count ; count--, pz += d_zwidth, pdest += screenwidth)
// {
// for (i=0 ; i<pix ; i++)
// {
// if (pz[i] <= izi)
// {
// pdest[i] = blendparticle( color, pdest[i] );
// }
// }
// }
xor eax, eax
mov ax, word ptr [esi]
cmp ax, izi
jg end_of_horiz_loop
{$ifdef ENABLE_ZWRITES_FOR_PARTICLES}
mov bp, izi
mov word ptr [esi], bp
{$endif}
mov eax, partparms.color
call [blendfunc]
add edi, 1
add esi, 2
end_of_horiz_loop:
dec ecx
jnz top_of_pix_horiz_loop
pop esi
pop edi
mov ebp, d_zwidth
shl ebp, 1
add esi, ebp
add edi, [r_screenwidth]
pop ecx
push ecx
push edi
push esi
dec edx
jnz top_of_pix_vert_loop
pop ecx
pop ecx
pop ecx
end_:
pop edi
pop esi
mov ebp, ebpsave
ret
end;
{$ENDIF} // __linux__
{$ELSE}
type
TBlendParticle = function(pcolor, dstcolor: Integer): Byte;
function BlendParticle33(pcolor, dstcolor: Integer): Byte;
begin
Result := PByte(Integer(vid.alphamap) + (pcolor + dstcolor * 256))^;
end;
function BlendParticle66(pcolor, dstcolor: Integer): Byte;
begin
Result := PByte(Integer(vid.alphamap) + (pcolor * 256 + dstcolor))^;
end;
function BlendParticle100(pcolor, dstcolor: Integer): Byte;
begin
Result := pcolor;
end;
(*
** R_DrawParticle
**
** Yes, this is amazingly slow, but it's the C reference
** implementation and should be both robust and vaguely
** understandable. The only time this path should be
** executed is if we're debugging on x86 or if we're
** recompiling and deploying on a non-x86 platform.
**
** To minimize error and improve readability I went the
** function pointer route. This exacts some overhead, but
** it pays off in clean and easy to understand code.
*)
procedure R_DrawParticle;
var
pparticle: particle_p;
level: Integer;
local: vec3_t;
transformed: vec3_t;
zi: Single;
pdest: PByte;
pz: PSmallInt;
color: Integer;
i, izi, pix: Integer;
count, u, v: Integer;
// blendparticle : TBlendParticle;
begin
pparticle := partparms.particle;
level := partparms.level;
color := pparticle^.color;
(*
** transform the particle
*)
VectorSubtract(pparticle^.origin, r_origin, local);
transformed[0] := DotProduct(local, r_pright);
transformed[1] := DotProduct(local, r_pup);
transformed[2] := DotProduct(local, r_ppn);
if (transformed[2] < PARTICLE_Z_CLIP) then
Exit;
(*
** bind the blend function pointer to the appropriate blender
*)
(* if (level = PARTICLE_33) then
blendparticle := BlendParticle33
else
begin
if (level = PARTICLE_66) then
blendparticle := BlendParticle66
else
blendparticle := BlendParticle100;
end;*)
(*
** project the point
*)
// FIXME: preadjust xcenter and ycenter
zi := 1.0 / transformed[2];
u := Trunc(xcenter + zi * transformed[0] + 0.5);
v := Trunc(ycenter - zi * transformed[1] + 0.5);
if ((v > d_vrectbottom_particle) or (u > d_vrectright_particle) or (v < d_vrecty) or (u < d_vrectx)) then
Exit;
(*
** compute addresses of zbuffer, framebuffer, and
** compute the Z-buffer reference value.
*)
pz := PSmallInt(Integer(d_pzbuffer) + (((Integer(d_zwidth) * v) + u) * SizeOf(SmallInt)));
pdest := PByte(Integer(d_viewbuffer) + (d_scantable[v] + u));
izi := Trunc(zi * $8000);
(*
** determine the screen area covered by the particle,
** which also means clamping to a min and max
*)
pix := _SAR(izi, d_pix_shift);
if (pix < d_pix_min) then
pix := d_pix_min
else
if (pix > d_pix_max) then
pix := d_pix_max;
(*
** render the appropriate pixels
*)
count := pix;
case (level) of
PARTICLE_33:
begin
while (count > 0) do
begin
//FIXME--do it in blocks of 8?
for I := 0 to pix - 1 do
begin
if (PSmallIntArray(pz)^[i] <= izi) then
begin
PSmallIntArray(pz)^[i] := izi;
PByteArray(pdest)^[i] := PByteArray(vid.alphamap)^[color + (Integer(PByteArray(pdest)^[i]) shl 8)];
end;
end;
Inc(Cardinal(pz), d_zwidth * SizeOf(SmallInt));
Inc(Integer(pdest), r_screenwidth);
Dec(count);
end;
end;
PARTICLE_66:
begin
while (count > 0) do
begin
for I := 0 to pix - 1 do
begin
if (PSmallIntArray(pz)^[i] <= izi) then
begin
PSmallIntArray(pz)^[i] := izi;
PByteArray(pdest)^[i] := PByteArray(vid.alphamap)^[(color shl 8) + Integer(PByteArray(pdest)^[i])];
end;
end;
Inc(Cardinal(pz), d_zwidth * SizeOf(SmallInt));
Inc(Integer(pdest), r_screenwidth);
Dec(count);
end;
end;
else //100
begin
while (count > 0) do
begin
for I := 0 to pix - 1 do
begin
if (PSmallIntArray(pz)^[i] <= izi) then
begin
PSmallIntArray(pz)^[i] := izi;
PByteArray(pdest)^[i] := color;
end;
end;
Inc(Cardinal(pz), d_zwidth * SizeOf(SmallInt));
Inc(Integer(pdest), r_screenwidth);
Dec(count);
end;
end;
end;
end;
{$ENDIF} // id386
(*
** R_DrawParticles
**
** Responsible for drawing all of the particles in the particle list
** throughout the world. Doesn't care if we're using the C path or
** if we're using the asm path, it simply assigns a function pointer
** and goes.
*)
procedure R_DrawParticles;
var
p: particle_p;
i: Integer;
// extern unsigned long fpu_sp24_cw, fpu_chop_cw;
begin
VectorScale(vright, xscaleshrink, r_pright);
VectorScale(vup, yscaleshrink, r_pup);
VectorCopy(vpn, r_ppn);
{$IFDEF id386}
{$IFNDEF __linux__}
asm
fldcw word ptr [fpu_sp24_cw]
end;
{$ENDIF}
{$ENDIF}
p := r_newrefdef.particles;
for i := 0 to r_newrefdef.num_particles - 1 do
begin
if (p^.alpha > 0.66) then
partparms.level := PARTICLE_OPAQUE
else
begin
if (p^.alpha > 0.33) then
partparms.level := PARTICLE_66
else
partparms.level := PARTICLE_33;
end;
partparms.particle := p;
partparms.color := p^.color;
{$IFDEF id386}
if (i < r_newrefdef.num_particles - 1) then
s_prefetch_address := Integer(p) + 1
else
s_prefetch_address := Integer(r_newrefdef.particles);
{$ENDIF}
R_DrawParticle;
Inc(Integer(p), SizeOf(particle_t));
end;
{$IFDEF id386}
asm
__asm fldcw word ptr [fpu_chop_cw]
end;
{$ENDIF}
(* r_newrefdef.particles
for (p=r_newrefdef.particles, i=0 ; i<r_newrefdef.num_particles ; i++,p++)
for (p=r_newrefdef.particles, i=0 ; i<r_newrefdef.num_particles ; i++,p++)
{
if ( p->alpha > 0.66 )
partparms.level = PARTICLE_OPAQUE;
else if ( p->alpha > 0.33 )
partparms.level = PARTICLE_66;
else
partparms.level = PARTICLE_33;
partparms.particle = p;
partparms.color = p->color;
#if id386 && !defined __linux__
if ( i < r_newrefdef.num_particles-1 )
s_prefetch_address = ( unsigned int ) ( p + 1 );
else
s_prefetch_address = ( unsigned int ) r_newrefdef.particles;
#endif
R_DrawParticle;
end;
#if id386 && !defined __linux__
__asm fldcw word ptr [fpu_chop_cw]
#endif*)
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -