289 lines
8.5 KiB
PHP
289 lines
8.5 KiB
PHP
{$ifdef PARAM_PHONGSSE}
|
|
{$asmmode intel}
|
|
//SSE rotate singles
|
|
const Shift231 = 1 + 8;
|
|
Shift312 = 2 + 16;
|
|
{$endif}
|
|
|
|
var
|
|
//Light source normal.
|
|
vL: TPoint3D_128; {xmm0}
|
|
//Light source position.
|
|
vLS: TPoint3D_128; {xmm1}
|
|
//Vector H is the unit normal to the hypothetical surface oriented
|
|
//halfway between the light direction vector (L) and the viewing vector (V).
|
|
vH: TPoint3D_128; {xmm2}
|
|
|
|
vN: TPoint3D_128; {xmm3} // surface normal
|
|
vP: TPoint3D_128; {xmm4} // position of lighted pixel
|
|
vV: TPoint3D_128; // viewer direction
|
|
{$ifdef PARAM_PHONGSSE}
|
|
LightDestFactor4: TPoint3D_128; // for multiplication
|
|
{$endif}
|
|
|
|
//Calculate LdotN and NnH
|
|
NH: Single;
|
|
{$ifndef PARAM_PHONGSSE}
|
|
vD: TPoint3D_128;
|
|
{$endif}
|
|
|
|
Iw, Ic: integer; // Iw: specular intensity, Ic: ambient+diffuse intensity
|
|
sIw: single; // floating point value for Iw
|
|
|
|
z, LdotN, NnH,
|
|
dist, distfactor, diffuseterm, specularterm: single;
|
|
eLight: TExpandedPixel;
|
|
mc,mcLeft,mcRight,mcTop,mcBottom: TBGRAPixel; ///map values
|
|
|
|
{$ifdef PARAM_SIMPLECOLOR}
|
|
eColor: TExpandedPixel;
|
|
{$else}
|
|
{$ifndef PARAM_SCANNER}
|
|
pcolormap: PBGRAPixel;
|
|
{$endif}
|
|
{$endif}
|
|
|
|
{$hints off}
|
|
function ComputePixel(x,y: integer; DiffuseLight, SpecularLight: Word; Alpha: Byte): TBGRAPixel; inline;
|
|
var ec: TExpandedPixel;
|
|
{$ifndef PARAM_SIMPLECOLOR}
|
|
eColor: TExpandedPixel;
|
|
{$endif}
|
|
begin
|
|
{$ifndef PARAM_SIMPLECOLOR}
|
|
{$ifdef PARAM_SCANNER}
|
|
eColor := GammaExpansion(ColorScan.ScanNextPixel);
|
|
{$else}
|
|
eColor := GammaExpansion(pcolormap^);
|
|
{$endif}
|
|
{$endif}
|
|
Alpha := ApplyOpacity(Alpha, eColor.alpha shr 8);
|
|
ec.red := (eColor.Red*DiffuseLight+eLight.Red*SpecularLight+PhongLightPrecisionDiv2) shr PhongLightPrecisionSh;
|
|
ec.green := (eColor.Green*DiffuseLight+eLight.Green*SpecularLight+PhongLightPrecisionDiv2) shr PhongLightPrecisionSh;
|
|
ec.blue := (eColor.Blue*DiffuseLight+eLight.Blue*SpecularLight+PhongLightPrecisionDiv2) shr PhongLightPrecisionSh;
|
|
ec.alpha := Alpha shl 8+Alpha;
|
|
result := GammaCompression(ec);
|
|
end;
|
|
{$hints on}
|
|
|
|
var
|
|
minx,miny,maxx,maxy: integer;
|
|
pmap: PBGRAPixel;
|
|
pdest: PBGRAPixel;
|
|
x,y : integer; // Coordinates of point in height map.
|
|
vS1,vS2: TPoint3D_128; // surface vectors (plane)
|
|
deltaDown: Int32or64;
|
|
IsLineUp,IsLineDown: boolean;
|
|
|
|
begin
|
|
if map = nil then exit;
|
|
{$ifndef PARAM_SIMPLECOLOR}
|
|
{$ifndef PARAM_SCANNER}
|
|
if (colorMap.Width < map.width) or (colorMap.Height < map.height) then
|
|
raise Exception.Create('Dimension mismatch');
|
|
{$endif}
|
|
{$endif}
|
|
|
|
if (map.width = 0) or (map.Height = 0) then exit;
|
|
if ofsX >= dest.ClipRect.Right then exit;
|
|
if ofsY >= dest.ClipRect.Bottom then exit;
|
|
if ofsX <= dest.ClipRect.Left-map.Width then exit;
|
|
if ofsY <= dest.ClipRect.Top-map.Height then exit;
|
|
|
|
minx := 0;
|
|
miny := 0;
|
|
maxx := map.Width-1;
|
|
maxy := map.Height-1;
|
|
if ofsX < dest.clipRect.Left then minx := dest.clipRect.Left-ofsX;
|
|
if ofsY < dest.clipRect.Top then miny := dest.clipRect.Top-ofsY;
|
|
if OfsX+maxx > dest.ClipRect.Right-1 then maxx := dest.ClipRect.Right-1-ofsX;
|
|
if OfsY+maxy > dest.ClipRect.Bottom-1 then maxy := dest.ClipRect.Bottom-1-ofsY;
|
|
|
|
eLight := GammaExpansion(LightColor);
|
|
{$ifdef PARAM_SIMPLECOLOR}
|
|
eColor := GammaExpansion(color);
|
|
{$endif}
|
|
|
|
//light origin
|
|
vLS := Point3D_128(LightPosition.X-ofsX,
|
|
LightPosition.Y-ofsY,
|
|
LightPositionZ);
|
|
|
|
//surface vectors
|
|
vS1 := Point3D_128(1,0,0);
|
|
vS2 := Point3D_128(0,1,0);
|
|
|
|
vV := Point3D_128(0,0,1);
|
|
|
|
dist := 0;
|
|
LdotN := 0;
|
|
NnH := 0;
|
|
|
|
{$ifdef PARAM_PHONGSSE}
|
|
LightDestFactor4 := Point3D_128(LightDestFactor,LightDestFactor,LightDestFactor,LightDestFactor);
|
|
{$endif}
|
|
|
|
if map.LineOrder = riloTopToBottom then
|
|
deltaDown := map.Width*sizeof(TBGRAPixel)
|
|
else
|
|
deltaDown := -map.Width*sizeof(TBGRAPixel);
|
|
for y := miny to maxy do
|
|
begin
|
|
//read map values
|
|
pmap := map.ScanLine[y]+minx;
|
|
mc := BGRAPixelTransparent;
|
|
mcRight := pmap^;
|
|
pdest := dest.ScanLine[y+ofsY]+ofsX+minx;
|
|
{$ifndef PARAM_SIMPLECOLOR}
|
|
{$ifdef PARAM_SCANNER}
|
|
ColorScan.ScanMoveTo(OfsX+minx,OfsY+Y);
|
|
{$else}
|
|
pcolormap := ColorMap.ScanLine[y];
|
|
{$endif}
|
|
{$endif}
|
|
IsLineUp := y > 0;
|
|
IsLineDown := y < map.Height-1;
|
|
mcTop := BGRAPixelTransparent;
|
|
mcBottom := BGRAPixelTransparent;
|
|
for x := minx to maxx do
|
|
begin
|
|
mcLeft := mc;
|
|
mc := mcRight;
|
|
if x < map.width-1 then
|
|
mcRight := (pmap+1)^ else
|
|
mcRight := BGRAPixelTransparent;
|
|
if mc.alpha = 0 then
|
|
begin
|
|
{$ifndef PARAM_SIMPLECOLOR}
|
|
{$ifdef PARAM_SCANNER}
|
|
ColorScan.ScanNextPixel;
|
|
{$else}
|
|
inc(pcolormap);
|
|
{$endif}
|
|
{$endif}
|
|
inc(pdest);
|
|
inc(pmap);
|
|
continue;
|
|
end;
|
|
|
|
//compute surface vectors
|
|
if IsLineUp then mcTop := pbgrapixel(pbyte(pmap)-deltaDown)^;
|
|
if IsLineDown then mcBottom := pbgrapixel(pbyte(pmap)+deltaDown)^;
|
|
inc(pmap);
|
|
|
|
z := MapHeight(mc)*mapAltitude;
|
|
if mcLeft.alpha = 0 then
|
|
begin
|
|
if mcRight.alpha = 0 then
|
|
vS1.z := 0
|
|
else
|
|
vS1.z := (MapHeight(mcRight)-MapHeight(mc))*mapAltitude*2;
|
|
end else
|
|
begin
|
|
if mcRight.alpha = 0 then
|
|
vS1.z := (MapHeight(mc)-MapHeight(mcLeft))*mapAltitude*2
|
|
else
|
|
vS1.z := (MapHeight(mcRight)-MapHeight(mcLeft))*mapAltitude;
|
|
end;
|
|
if mcTop.alpha = 0 then
|
|
begin
|
|
if mcBottom.alpha = 0 then
|
|
vS2.z := 0
|
|
else
|
|
vS2.z := (MapHeight(mcBottom)-MapHeight(mc))*mapAltitude*2;
|
|
end else
|
|
begin
|
|
if mcBottom.alpha = 0 then
|
|
vS2.z := (MapHeight(mc)-MapHeight(mcTop))*mapAltitude*2
|
|
else
|
|
vS2.z := (MapHeight(mcBottom)-MapHeight(mcTop))*mapAltitude;
|
|
end;
|
|
|
|
//position vector
|
|
vP := Point3D_128(x, y, z);
|
|
{$ifdef PARAM_PHONGSSE}
|
|
if UseSSE3 then
|
|
begin
|
|
{$DEFINE PARAM_USESSE3}
|
|
asm
|
|
movups xmm1, vLS
|
|
end;
|
|
{$i phongdrawsse.inc}
|
|
{$UNDEF PARAM_USESSE3}
|
|
end else
|
|
begin
|
|
asm
|
|
movups xmm1, vLS
|
|
end;
|
|
{$i phongdrawsse.inc}
|
|
end;
|
|
{$else}
|
|
vP := Point3D_128(x, y, z);
|
|
vL := vLS- vP*LightDestFactor;
|
|
Normalize3D_128(vL);
|
|
|
|
//compute bisector of angle between light and observer
|
|
vH := vL + vV;
|
|
Normalize3D_128(vH);
|
|
|
|
// compute normal vector to the surface
|
|
VectProduct3D_128(vS1,vS2,vN);
|
|
Normalize3D_128(vN);
|
|
|
|
//Calculate LdotN and NnH
|
|
LdotN := DotProduct3D_128(vN,vL);
|
|
vD := vLS-vP;
|
|
dist := sqrt(DotProduct3D_128(vD,vD));
|
|
|
|
NH := DotProduct3D_128(vH,vN);
|
|
{$endif}
|
|
|
|
if NH <= 0 then
|
|
NnH := 0
|
|
else
|
|
NnH := exp(SpecularIndex*ln(NH)); //to be optimized
|
|
|
|
distfactor := LightSourceIntensity / (dist*LightSourceDistanceFactor + LightSourceDistanceTerm);
|
|
|
|
if (LdotN <= 0) then //Point is not illuminated by light source.
|
|
//Use negative diffuse for contrast
|
|
diffuseterm := distfactor * NegativeDiffusionFactor * LdotN
|
|
else
|
|
diffuseterm := distfactor * DiffusionFactor * LdotN;
|
|
Ic := round((AmbientFactor + diffuseterm)*PhongLightPrecision);
|
|
|
|
//specular (reflection)
|
|
specularterm := distfactor * SpecularFactor * NnH;
|
|
sIw := specularterm*PhongLightPrecision;
|
|
if sIw > PhongLightPrecision then Iw := PhongLightPrecision else
|
|
Iw := round(sIw);
|
|
|
|
//intensity bounds (0..PhongLightPrecision)
|
|
If Ic < 0 then Ic := 0;
|
|
If Ic > PhongLightPrecision then
|
|
begin
|
|
If DiffuseSaturation then
|
|
begin
|
|
Iw := Iw+(Ic-PhongLightPrecision);
|
|
if Iw > PhongLightPrecision then Iw := PhongLightPrecision;
|
|
end;
|
|
Ic := PhongLightPrecision;
|
|
end;
|
|
Ic := Ic*(PhongLightPrecision-Iw) shr PhongLightPrecisionSh;
|
|
|
|
DrawPixelInlineWithAlphaCheck(pdest, ComputePixel(x,y,Ic,Iw,mc.alpha));
|
|
{$ifndef PARAM_SIMPLECOLOR}
|
|
{$ifndef PARAM_SCANNER}
|
|
inc(pcolormap);
|
|
{$endif}
|
|
{$endif}
|
|
inc(pdest); //go to next pixel
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
{$undef PARAM_PHONGSSE}
|
|
{$undef PARAM_SIMPLECOLOR}
|
|
{$undef PARAM_SCANNER}
|
|
|