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