| 1 | {$ifdef PARAM_PHONGSSE}
|
|---|
| 2 | {$asmmode intel}
|
|---|
| 3 | //SSE rotate singles
|
|---|
| 4 | const Shift231 = 1 + 8;
|
|---|
| 5 | Shift312 = 2 + 16;
|
|---|
| 6 | {$endif}
|
|---|
| 7 |
|
|---|
| 8 | var
|
|---|
| 9 | //Light source normal.
|
|---|
| 10 | vL: TPoint3D_128; {xmm0}
|
|---|
| 11 | //Light source position.
|
|---|
| 12 | vLS: TPoint3D_128; {xmm1}
|
|---|
| 13 | //Vector H is the unit normal to the hypothetical surface oriented
|
|---|
| 14 | //halfway between the light direction vector (L) and the viewing vector (V).
|
|---|
| 15 | vH: TPoint3D_128; {xmm2}
|
|---|
| 16 |
|
|---|
| 17 | vN: TPoint3D_128; {xmm3} // surface normal
|
|---|
| 18 | vP: TPoint3D_128; {xmm4} // position of lighted pixel
|
|---|
| 19 | vV: TPoint3D_128; // viewer direction
|
|---|
| 20 | {$ifdef PARAM_PHONGSSE}
|
|---|
| 21 | LightDestFactor4: TPoint3D_128; // for multiplication
|
|---|
| 22 | {$endif}
|
|---|
| 23 |
|
|---|
| 24 | //Calculate LdotN and NnH
|
|---|
| 25 | NH: Single;
|
|---|
| 26 | {$ifndef PARAM_PHONGSSE}
|
|---|
| 27 | vD: TPoint3D_128;
|
|---|
| 28 | {$endif}
|
|---|
| 29 |
|
|---|
| 30 | Iw, Ic: integer; // Iw: specular intensity, Ic: ambient+diffuse intensity
|
|---|
| 31 | sIw: single; // floating point value for Iw
|
|---|
| 32 |
|
|---|
| 33 | z, LdotN, NnH,
|
|---|
| 34 | dist, distfactor, diffuseterm, specularterm: single;
|
|---|
| 35 | eLight: TExpandedPixel;
|
|---|
| 36 | mc,mcLeft,mcRight,mcTop,mcBottom: TBGRAPixel; ///map values
|
|---|
| 37 |
|
|---|
| 38 | {$ifdef PARAM_SIMPLECOLOR}
|
|---|
| 39 | eColor: TExpandedPixel;
|
|---|
| 40 | {$else}
|
|---|
| 41 | {$ifndef PARAM_SCANNER}
|
|---|
| 42 | pcolormap: PBGRAPixel;
|
|---|
| 43 | {$endif}
|
|---|
| 44 | {$endif}
|
|---|
| 45 |
|
|---|
| 46 | {$hints off}
|
|---|
| 47 | function ComputePixel(x,y: integer; DiffuseLight, SpecularLight: Word; Alpha: Byte): TBGRAPixel; inline;
|
|---|
| 48 | var ec: TExpandedPixel;
|
|---|
| 49 | {$ifndef PARAM_SIMPLECOLOR}
|
|---|
| 50 | eColor: TExpandedPixel;
|
|---|
| 51 | {$endif}
|
|---|
| 52 | begin
|
|---|
| 53 | {$ifndef PARAM_SIMPLECOLOR}
|
|---|
| 54 | {$ifdef PARAM_SCANNER}
|
|---|
| 55 | eColor := GammaExpansion(ColorScan.ScanNextPixel);
|
|---|
| 56 | {$else}
|
|---|
| 57 | eColor := GammaExpansion(pcolormap^);
|
|---|
| 58 | {$endif}
|
|---|
| 59 | {$endif}
|
|---|
| 60 | Alpha := ApplyOpacity(Alpha, eColor.alpha shr 8);
|
|---|
| 61 | ec.red := (eColor.Red*DiffuseLight+eLight.Red*SpecularLight+PhongLightPrecisionDiv2) shr PhongLightPrecisionSh;
|
|---|
| 62 | ec.green := (eColor.Green*DiffuseLight+eLight.Green*SpecularLight+PhongLightPrecisionDiv2) shr PhongLightPrecisionSh;
|
|---|
| 63 | ec.blue := (eColor.Blue*DiffuseLight+eLight.Blue*SpecularLight+PhongLightPrecisionDiv2) shr PhongLightPrecisionSh;
|
|---|
| 64 | ec.alpha := Alpha shl 8+Alpha;
|
|---|
| 65 | result := GammaCompression(ec);
|
|---|
| 66 | end;
|
|---|
| 67 | {$hints on}
|
|---|
| 68 |
|
|---|
| 69 | var
|
|---|
| 70 | minx,miny,maxx,maxy: integer;
|
|---|
| 71 | pmap: PBGRAPixel;
|
|---|
| 72 | pdest: PBGRAPixel;
|
|---|
| 73 | x,y : integer; // Coordinates of point in height map.
|
|---|
| 74 | vS1,vS2: TPoint3D_128; // surface vectors (plane)
|
|---|
| 75 | deltaDown: Int32or64;
|
|---|
| 76 | IsLineUp,IsLineDown: boolean;
|
|---|
| 77 |
|
|---|
| 78 | begin
|
|---|
| 79 | if map = nil then exit;
|
|---|
| 80 | {$ifndef PARAM_SIMPLECOLOR}
|
|---|
| 81 | {$ifndef PARAM_SCANNER}
|
|---|
| 82 | if (colorMap.Width < map.width) or (colorMap.Height < map.height) then
|
|---|
| 83 | raise Exception.Create('Dimension mismatch');
|
|---|
| 84 | {$endif}
|
|---|
| 85 | {$endif}
|
|---|
| 86 |
|
|---|
| 87 | if (map.width = 0) or (map.Height = 0) then exit;
|
|---|
| 88 | if ofsX >= dest.ClipRect.Right then exit;
|
|---|
| 89 | if ofsY >= dest.ClipRect.Bottom then exit;
|
|---|
| 90 | if ofsX <= dest.ClipRect.Left-map.Width then exit;
|
|---|
| 91 | if ofsY <= dest.ClipRect.Top-map.Height then exit;
|
|---|
| 92 |
|
|---|
| 93 | minx := 0;
|
|---|
| 94 | miny := 0;
|
|---|
| 95 | maxx := map.Width-1;
|
|---|
| 96 | maxy := map.Height-1;
|
|---|
| 97 | if ofsX < dest.clipRect.Left then minx := dest.clipRect.Left-ofsX;
|
|---|
| 98 | if ofsY < dest.clipRect.Top then miny := dest.clipRect.Top-ofsY;
|
|---|
| 99 | if OfsX+maxx > dest.ClipRect.Right-1 then maxx := dest.ClipRect.Right-1-ofsX;
|
|---|
| 100 | if OfsY+maxy > dest.ClipRect.Bottom-1 then maxy := dest.ClipRect.Bottom-1-ofsY;
|
|---|
| 101 |
|
|---|
| 102 | eLight := GammaExpansion(LightColor);
|
|---|
| 103 | {$ifdef PARAM_SIMPLECOLOR}
|
|---|
| 104 | eColor := GammaExpansion(color);
|
|---|
| 105 | {$endif}
|
|---|
| 106 |
|
|---|
| 107 | //light origin
|
|---|
| 108 | vLS := Point3D_128(LightPosition.X-ofsX,
|
|---|
| 109 | LightPosition.Y-ofsY,
|
|---|
| 110 | LightPositionZ);
|
|---|
| 111 |
|
|---|
| 112 | //surface vectors
|
|---|
| 113 | vS1 := Point3D_128(1,0,0);
|
|---|
| 114 | vS2 := Point3D_128(0,1,0);
|
|---|
| 115 |
|
|---|
| 116 | vV := Point3D_128(0,0,1);
|
|---|
| 117 |
|
|---|
| 118 | dist := 0;
|
|---|
| 119 | LdotN := 0;
|
|---|
| 120 | NnH := 0;
|
|---|
| 121 |
|
|---|
| 122 | {$ifdef PARAM_PHONGSSE}
|
|---|
| 123 | LightDestFactor4 := Point3D_128(LightDestFactor,LightDestFactor,LightDestFactor,LightDestFactor);
|
|---|
| 124 | {$endif}
|
|---|
| 125 |
|
|---|
| 126 | if map.LineOrder = riloTopToBottom then
|
|---|
| 127 | deltaDown := map.Width*sizeof(TBGRAPixel)
|
|---|
| 128 | else
|
|---|
| 129 | deltaDown := -map.Width*sizeof(TBGRAPixel);
|
|---|
| 130 | for y := miny to maxy do
|
|---|
| 131 | begin
|
|---|
| 132 | //read map values
|
|---|
| 133 | pmap := map.ScanLine[y]+minx;
|
|---|
| 134 | mc := BGRAPixelTransparent;
|
|---|
| 135 | mcRight := pmap^;
|
|---|
| 136 | pdest := dest.ScanLine[y+ofsY]+ofsX+minx;
|
|---|
| 137 | {$ifndef PARAM_SIMPLECOLOR}
|
|---|
| 138 | {$ifdef PARAM_SCANNER}
|
|---|
| 139 | ColorScan.ScanMoveTo(OfsX+minx,OfsY+Y);
|
|---|
| 140 | {$else}
|
|---|
| 141 | pcolormap := ColorMap.ScanLine[y];
|
|---|
| 142 | {$endif}
|
|---|
| 143 | {$endif}
|
|---|
| 144 | IsLineUp := y > 0;
|
|---|
| 145 | IsLineDown := y < map.Height-1;
|
|---|
| 146 | mcTop := BGRAPixelTransparent;
|
|---|
| 147 | mcBottom := BGRAPixelTransparent;
|
|---|
| 148 | for x := minx to maxx do
|
|---|
| 149 | begin
|
|---|
| 150 | mcLeft := mc;
|
|---|
| 151 | mc := mcRight;
|
|---|
| 152 | if x < map.width-1 then
|
|---|
| 153 | mcRight := (pmap+1)^ else
|
|---|
| 154 | mcRight := BGRAPixelTransparent;
|
|---|
| 155 | if mc.alpha = 0 then
|
|---|
| 156 | begin
|
|---|
| 157 | {$ifndef PARAM_SIMPLECOLOR}
|
|---|
| 158 | {$ifdef PARAM_SCANNER}
|
|---|
| 159 | ColorScan.ScanNextPixel;
|
|---|
| 160 | {$else}
|
|---|
| 161 | inc(pcolormap);
|
|---|
| 162 | {$endif}
|
|---|
| 163 | {$endif}
|
|---|
| 164 | inc(pdest);
|
|---|
| 165 | inc(pmap);
|
|---|
| 166 | continue;
|
|---|
| 167 | end;
|
|---|
| 168 |
|
|---|
| 169 | //compute surface vectors
|
|---|
| 170 | if IsLineUp then mcTop := pbgrapixel(pbyte(pmap)-deltaDown)^;
|
|---|
| 171 | if IsLineDown then mcBottom := pbgrapixel(pbyte(pmap)+deltaDown)^;
|
|---|
| 172 | inc(pmap);
|
|---|
| 173 |
|
|---|
| 174 | z := MapHeight(mc)*mapAltitude;
|
|---|
| 175 | if mcLeft.alpha = 0 then
|
|---|
| 176 | begin
|
|---|
| 177 | if mcRight.alpha = 0 then
|
|---|
| 178 | vS1.z := 0
|
|---|
| 179 | else
|
|---|
| 180 | vS1.z := (MapHeight(mcRight)-MapHeight(mc))*mapAltitude*2;
|
|---|
| 181 | end else
|
|---|
| 182 | begin
|
|---|
| 183 | if mcRight.alpha = 0 then
|
|---|
| 184 | vS1.z := (MapHeight(mc)-MapHeight(mcLeft))*mapAltitude*2
|
|---|
| 185 | else
|
|---|
| 186 | vS1.z := (MapHeight(mcRight)-MapHeight(mcLeft))*mapAltitude;
|
|---|
| 187 | end;
|
|---|
| 188 | if mcTop.alpha = 0 then
|
|---|
| 189 | begin
|
|---|
| 190 | if mcBottom.alpha = 0 then
|
|---|
| 191 | vS2.z := 0
|
|---|
| 192 | else
|
|---|
| 193 | vS2.z := (MapHeight(mcBottom)-MapHeight(mc))*mapAltitude*2;
|
|---|
| 194 | end else
|
|---|
| 195 | begin
|
|---|
| 196 | if mcBottom.alpha = 0 then
|
|---|
| 197 | vS2.z := (MapHeight(mc)-MapHeight(mcTop))*mapAltitude*2
|
|---|
| 198 | else
|
|---|
| 199 | vS2.z := (MapHeight(mcBottom)-MapHeight(mcTop))*mapAltitude;
|
|---|
| 200 | end;
|
|---|
| 201 |
|
|---|
| 202 | //position vector
|
|---|
| 203 | vP := Point3D_128(x, y, z);
|
|---|
| 204 | {$ifdef PARAM_PHONGSSE}
|
|---|
| 205 | if UseSSE3 then
|
|---|
| 206 | begin
|
|---|
| 207 | {$DEFINE PARAM_USESSE3}
|
|---|
| 208 | asm
|
|---|
| 209 | movups xmm1, vLS
|
|---|
| 210 | end;
|
|---|
| 211 | {$i phongdrawsse.inc}
|
|---|
| 212 | {$UNDEF PARAM_USESSE3}
|
|---|
| 213 | end else
|
|---|
| 214 | begin
|
|---|
| 215 | asm
|
|---|
| 216 | movups xmm1, vLS
|
|---|
| 217 | end;
|
|---|
| 218 | {$i phongdrawsse.inc}
|
|---|
| 219 | end;
|
|---|
| 220 | {$else}
|
|---|
| 221 | vP := Point3D_128(x, y, z);
|
|---|
| 222 | vL := vLS- vP*LightDestFactor;
|
|---|
| 223 | Normalize3D_128(vL);
|
|---|
| 224 |
|
|---|
| 225 | //compute bisector of angle between light and observer
|
|---|
| 226 | vH := vL + vV;
|
|---|
| 227 | Normalize3D_128(vH);
|
|---|
| 228 |
|
|---|
| 229 | // compute normal vector to the surface
|
|---|
| 230 | VectProduct3D_128(vS1,vS2,vN);
|
|---|
| 231 | Normalize3D_128(vN);
|
|---|
| 232 |
|
|---|
| 233 | //Calculate LdotN and NnH
|
|---|
| 234 | LdotN := DotProduct3D_128(vN,vL);
|
|---|
| 235 | vD := vLS-vP;
|
|---|
| 236 | dist := sqrt(DotProduct3D_128(vD,vD));
|
|---|
| 237 |
|
|---|
| 238 | NH := DotProduct3D_128(vH,vN);
|
|---|
| 239 | {$endif}
|
|---|
| 240 |
|
|---|
| 241 | if NH <= 0 then
|
|---|
| 242 | NnH := 0
|
|---|
| 243 | else
|
|---|
| 244 | NnH := exp(SpecularIndex*ln(NH)); //to be optimized
|
|---|
| 245 |
|
|---|
| 246 | distfactor := LightSourceIntensity / (dist*LightSourceDistanceFactor + LightSourceDistanceTerm);
|
|---|
| 247 |
|
|---|
| 248 | if (LdotN <= 0) then //Point is not illuminated by light source.
|
|---|
| 249 | //Use negative diffuse for contrast
|
|---|
| 250 | diffuseterm := distfactor * NegativeDiffusionFactor * LdotN
|
|---|
| 251 | else
|
|---|
| 252 | diffuseterm := distfactor * DiffusionFactor * LdotN;
|
|---|
| 253 | Ic := round((AmbientFactor + diffuseterm)*PhongLightPrecision);
|
|---|
| 254 |
|
|---|
| 255 | //specular (reflection)
|
|---|
| 256 | specularterm := distfactor * SpecularFactor * NnH;
|
|---|
| 257 | sIw := specularterm*PhongLightPrecision;
|
|---|
| 258 | if sIw > PhongLightPrecision then Iw := PhongLightPrecision else
|
|---|
| 259 | Iw := round(sIw);
|
|---|
| 260 |
|
|---|
| 261 | //intensity bounds (0..PhongLightPrecision)
|
|---|
| 262 | If Ic < 0 then Ic := 0;
|
|---|
| 263 | If Ic > PhongLightPrecision then
|
|---|
| 264 | begin
|
|---|
| 265 | If DiffuseSaturation then
|
|---|
| 266 | begin
|
|---|
| 267 | Iw := Iw+(Ic-PhongLightPrecision);
|
|---|
| 268 | if Iw > PhongLightPrecision then Iw := PhongLightPrecision;
|
|---|
| 269 | end;
|
|---|
| 270 | Ic := PhongLightPrecision;
|
|---|
| 271 | end;
|
|---|
| 272 | Ic := Ic*(PhongLightPrecision-Iw) shr PhongLightPrecisionSh;
|
|---|
| 273 |
|
|---|
| 274 | DrawPixelInlineWithAlphaCheck(pdest, ComputePixel(x,y,Ic,Iw,mc.alpha));
|
|---|
| 275 | {$ifndef PARAM_SIMPLECOLOR}
|
|---|
| 276 | {$ifndef PARAM_SCANNER}
|
|---|
| 277 | inc(pcolormap);
|
|---|
| 278 | {$endif}
|
|---|
| 279 | {$endif}
|
|---|
| 280 | inc(pdest); //go to next pixel
|
|---|
| 281 | end;
|
|---|
| 282 | end;
|
|---|
| 283 | end;
|
|---|
| 284 |
|
|---|
| 285 | {$undef PARAM_PHONGSSE}
|
|---|
| 286 | {$undef PARAM_SIMPLECOLOR}
|
|---|
| 287 | {$undef PARAM_SCANNER}
|
|---|
| 288 |
|
|---|