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 |
|
---|