GXS.zBuffer.pas 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307
  1. //
  2. // The graphics engine GLXEngine. The unit of GXScene for Delphi
  3. //
  4. unit GXS.zBuffer;
  5. (*
  6. ZBuffer retrieval and computations.
  7. See readme.txt in the Demos/SpecialsFX/Shadows directory.
  8. By René Lindsay.
  9. *)
  10. //--------These formulas are the key to making use of the z-Buffer--------
  11. //
  12. // dst (d): world distance
  13. // dov : depth of view (distance between Far-plane and Near-plane)
  14. // np : near plane
  15. // fp : far plane (dov+np)
  16. //
  17. //------------------------
  18. //dst:=(fp*np)/(fp-z*dov); //calc from z-buffer value to frustrum depth
  19. //z :=(1-np/d)/(1-np/fp); //calc from frustrum depth to z-buffer value
  20. //------------------------ z:=1-(fp/d-1)/(fp/np-1); //old FtoZ
  21. //------------------------------------------------------------------------
  22. interface
  23. {$I Stage.Defines.inc}
  24. uses
  25. System.Classes,
  26. System.SysUtils,
  27. System.Math,
  28. Stage.OpenGL4,
  29. Stage.VectorTypes,
  30. GXS.PersistentClasses,
  31. Stage.VectorGeometry,
  32. GXS.Coordinates,
  33. GXS.Color,
  34. GXS.Scene,
  35. GXS.XOpenGL,
  36. GXS.Graphics,
  37. GXS.Objects,
  38. GXS.Context,
  39. GXS.SceneViewer,
  40. GXS.RenderContextInfo,
  41. GXS.State,
  42. Stage.TextureFormat;
  43. type
  44. EZBufferException = class(Exception);
  45. TZArray = array[0..MaxInt shr 3] of Single;
  46. PZArray = ^TZArray;
  47. TZArrayIdx = array of PZArray;
  48. TAArray = array[0..MaxInt shr 3] of Byte;
  49. PAArray = ^TAArray;
  50. TAArrayIdx = array of PAArray;
  51. TOptimise = (opNone, op4in1, op9in1, op16in1);
  52. TgxZBuffer = class(TPersistent)
  53. private
  54. FData: PZArray;
  55. FDataIdx, FDataInvIdx: TZArrayIdx;
  56. FWidth, FHeight: Integer;
  57. FDataSize: Integer;
  58. ang1, ang2, scal, c1, s1, c2, s2, vw, vh: single; //VectorToScreen variables;
  59. lt, rt, lb, rb: TAffineVector; //ScreenToVector corner vectors;
  60. UpVec, riVec: TAffineVector;
  61. ltW, rtW, lbW, rbW: TAffineVector; //ScreenToVector corner vectors;(Warped)
  62. UpVecW, riVecW: TAffineVector;
  63. OrthInvDov, OrthAddX, OrthMulX, OrthAddY, OrthMulY: single;
  64. dov, np, fp, NpFp, OneMinNp_Fp, invOneMinNp_Fp: single; //Calc Variables;
  65. cam: TgxCamera;
  66. procedure DoCalcVectors;
  67. protected
  68. procedure PrepareBufferMemory;
  69. procedure SetWidth(val: Integer);
  70. procedure SetHeight(const val: Integer);
  71. public
  72. SceneViewer: TgxSceneViewer;
  73. MemoryViewer: TgxMemoryViewer;
  74. Buffer: TgxSceneBuffer;
  75. Normal: TAffineVector; //Absolute direction of camera
  76. constructor Create;
  77. destructor Destroy; override;
  78. procedure LinkToViewer(viewer: TgxSceneViewer); overload;
  79. procedure LinkToViewer(viewer: TgxMemoryViewer); overload;
  80. function GetDepthBuffer(CalcVectors: Boolean; ContextIsActive: boolean):
  81. PZArray;
  82. function GetPixelzDepth(x, y: integer): Single;
  83. function PixelToDistance_OLD(x, y: integer): Single;
  84. function PixelToDistance(x, y: integer): Single;
  85. property Width: Integer read FWidth write SetWidth;
  86. property Height: Integer read FHeight write SetHeight;
  87. property DataSize: Integer read FDataSize;
  88. property Data: PZArray read FData;
  89. property DataIdx: TZArrayIdx read FDataIdx;
  90. property DataInvIdx: TZArrayIdx read FDataIdx;
  91. procedure Refresh;
  92. function FastScreenToVector(x, y: Integer): TAffineVector;
  93. function FastVectorToScreen(vec: TAffineVector): TAffineVector;
  94. function PixelToWorld(const x, y: Integer): TAffineVector;
  95. function WorldToPixel(const aPoint: TAffineVector; out pixX, pixY: integer;
  96. out pixZ: single): boolean;
  97. function WorldToPixelZ(const aPoint: TAffineVector; out pixX, pixY: integer;
  98. out pixZ: single): boolean; overload;
  99. function WorldToPixelZ(const aPoint: TAffineVector; out pixX, pixY: single;
  100. out pixZ: single): boolean; overload;
  101. function OrthWorldToPixelZ(const aPoint: TAffineVector; out pixX, pixY:
  102. single; out pixZ: single): boolean;
  103. end;
  104. TgxZShadows = class(TgxBaseSceneObject)
  105. private
  106. FViewer: TgxSceneViewer;
  107. FCaster: TgxMemoryViewer;
  108. FDepthFade: Boolean;
  109. FFrustShadow: Boolean;
  110. FSkyShadow: Boolean;
  111. FOptimise: TOptimise;
  112. FData: PAArray;
  113. FDataIdx, FDataInvIdx: TAArrayIdx;
  114. FDataSize: Integer;
  115. FWidth: integer;
  116. FHeight: integer;
  117. FXRes: integer;
  118. FYRes: integer;
  119. Fsoft: boolean;
  120. FTolerance: single;
  121. FColor: TgxColor;
  122. SCol: TgxPixel32;
  123. //stepX, stepY :single;
  124. FTexturePrepared: Boolean;
  125. FTexHandle: TgxTextureHandle;
  126. protected
  127. procedure PrepareAlphaMemory;
  128. function GetViewer: TgxSceneViewer;
  129. procedure SetViewer(const val: TgxSceneViewer);
  130. function GetCaster: TgxMemoryViewer;
  131. procedure SetCaster(const val: TgxMemoryViewer);
  132. procedure CalcShadowTexture(var rci: TgxRenderContextInfo);
  133. function HardSet(const x, y: integer): Byte;
  134. function SoftTest(const x, y: integer): Byte;
  135. procedure SetWidth(const val: integer);
  136. procedure SetHeight(const val: integer);
  137. procedure SetXRes(const val: integer);
  138. procedure SetYRes(const val: integer);
  139. procedure SetSoft(const val: boolean);
  140. procedure BindTexture;
  141. public
  142. ViewerZBuf: TgxZBuffer;
  143. CasterZBuf: TgxZBuffer;
  144. constructor Create(AOwner: TComponent); override;
  145. destructor Destroy; override;
  146. procedure DoRender(var ARci: TgxRenderContextInfo; ARenderSelf,
  147. ARenderChildren: Boolean); override;
  148. published
  149. property Viewer: TgxSceneViewer read GetViewer write SetViewer;
  150. property Caster: TgxMemoryViewer read GetCaster write SetCaster;
  151. property FrustShadow: Boolean read FFrustShadow write FFrustShadow;
  152. property SkyShadow: Boolean read FSkyShadow write FSkyShadow;
  153. property Optimise: TOptimise read FOptimise write FOptimise;
  154. property Width: integer read FWidth write SetWidth;
  155. property Height: integer read FHeight write SetHeight;
  156. property Color: TgxColor read FColor write FColor;
  157. // property Xres :integer read FXRes write SetXRes;// default 64;
  158. // property Yres :integer read FYRes write SetYRes;// default 64;
  159. property Soft: Boolean read Fsoft write SetSoft;
  160. property Tolerance: single read FTolerance write FTolerance;
  161. // property Material;
  162. property ObjectsSorting;
  163. property Visible;
  164. property DepthFade: Boolean read FDepthFade write FDepthFade;
  165. function CastShadow: boolean;
  166. end;
  167. //======================================================================
  168. implementation
  169. //======================================================================
  170. constructor TgxZBuffer.Create;
  171. begin
  172. inherited Create;
  173. self.FWidth := 0;
  174. self.FHeight := 0;
  175. self.FDataSize := 0;
  176. self.cam := nil;
  177. self.SceneViewer := nil;
  178. self.MemoryViewer := nil;
  179. self.buffer := nil;
  180. // self.DoCalcVectors;
  181. end;
  182. procedure TgxZBuffer.LinkToViewer(viewer: TgxSceneViewer); // overload;
  183. begin
  184. if ((FWidth <> Viewer.Buffer.Width) or (FHeight <> Viewer.Buffer.Height)) then
  185. begin
  186. FWidth := Viewer.Buffer.Width;
  187. FHeight := Viewer.Buffer.Height;
  188. PrepareBufferMemory;
  189. end;
  190. cam := Viewer.camera;
  191. SceneViewer := Viewer;
  192. Buffer := Viewer.Buffer;
  193. self.DoCalcVectors;
  194. end;
  195. procedure TgxZBuffer.LinkToViewer(viewer: TgxMemoryViewer); // overload;
  196. begin
  197. if ((FWidth <> Viewer.width) or (FHeight <> Viewer.height)) then
  198. begin
  199. FWidth := Viewer.width;
  200. FHeight := Viewer.height;
  201. PrepareBufferMemory;
  202. end;
  203. cam := Viewer.camera;
  204. MemoryViewer := Viewer;
  205. Buffer := Viewer.Buffer;
  206. self.DoCalcVectors;
  207. end;
  208. destructor TgxZBuffer.Destroy;
  209. begin
  210. FreeMem(FData);
  211. inherited Destroy;
  212. end;
  213. procedure TgxZBuffer.PrepareBufferMemory;
  214. var
  215. i: Integer;
  216. begin
  217. FDataSize := FWidth * FHeight * 4;
  218. ReallocMem(FData, FDataSize);
  219. SetLength(FDataIdx, FHeight + 2);
  220. SetLength(FDataInvIdx, FHeight + 2);
  221. for i := 0 to FHeight - 1 do
  222. begin
  223. FDataIdx[i] := @FData[i * FWidth]; // range: [0..height-1]
  224. FDataInvIdx[i] := @FData[(FHeight - i - 1) * FWidth]; // range: [0..height-1]
  225. end;
  226. FDataIdx[FHeight] := FDataIdx[FHeight - 1];
  227. FDataInvIdx[FHeight] := FDataInvIdx[FHeight - 1];
  228. end;
  229. procedure TgxZBuffer.SetWidth(val: Integer);
  230. begin
  231. if val <> FWidth then
  232. begin
  233. Assert(val >= 0);
  234. FWidth := val;
  235. PrepareBufferMemory;
  236. end;
  237. end;
  238. procedure TgxZBuffer.SetHeight(const val: Integer);
  239. begin
  240. if val <> FHeight then
  241. begin
  242. Assert(val >= 0);
  243. FHeight := val;
  244. PrepareBufferMemory;
  245. end;
  246. end;
  247. function TgxZBuffer.GetDepthBuffer(CalcVectors: Boolean; ContextIsActive:
  248. boolean): PZArray;
  249. begin
  250. if ContextIsActive = True then
  251. begin
  252. glReadPixels(0, 0, FWidth, FHeight, GL_DEPTH_COMPONENT, GL_FLOAT, FData);
  253. end
  254. else
  255. begin
  256. Buffer.RenderingContext.Activate;
  257. try
  258. glReadPixels(0, 0, FWidth, FHeight, GL_DEPTH_COMPONENT, GL_FLOAT, FData);
  259. finally
  260. Buffer.RenderingContext.Deactivate;
  261. end;
  262. end;
  263. if CalcVectors = True then
  264. DoCalcVectors;
  265. Result := FData;
  266. end;
  267. function TgxZBuffer.GetPixelzDepth(x, y: integer): Single;
  268. begin
  269. if (Cardinal(x) < Cardinal(FWidth)) and (Cardinal(y) < Cardinal(FHeight)) then
  270. Result := FDataInvIdx[y]^[x]
  271. else
  272. Result := 0;
  273. end;
  274. function TgxZBuffer.PixelToDistance_OLD(x, y: integer): Single;
  275. var
  276. z, dst, camAng, wrpdst: single;
  277. vec: TAffineVector;
  278. begin
  279. if ((x < 0) or (x > FWidth) or (y < 0) or (y > FWidth)) then
  280. result := 0
  281. else
  282. begin
  283. z := FData^[x + (FHeight - y) * FWidth]; //fetch pixel z-depth
  284. dst := (NpFp) / (fp - z * dov); //calc from z-buffer value to frustrum depth
  285. vec := FastScreenToVector(x, y);
  286. camAng := VectorAngleCosine(normal, vec);
  287. wrpdst := dst / camAng; //compensate for flat frustrum face
  288. result := wrpdst;
  289. end;
  290. end;
  291. function TgxZBuffer.PixelToDistance(x, y: integer): Single;
  292. var
  293. z, dst: single;
  294. xx, yy, zz: single;
  295. fy: integer;
  296. begin
  297. if ((x < 0) or (x >= FWidth) or (y < 0) or (y >= FHeight)) then
  298. result := 0
  299. else
  300. begin
  301. fy := FHeight - y;
  302. z := FData^[x + fy * FWidth]; //fetch pixel z-depth
  303. if z < 1 then
  304. begin
  305. dst := (NpFp) / (fp - z * dov);
  306. //calc from z-buffer value to frustrum depth
  307. xx := (lbW.X + riVecW.X * x + UpVecW.X * fy);
  308. yy := (lbW.Y + riVecW.Y * x + UpVecW.Y * fy);
  309. zz := (lbW.Z + riVecW.Z * x + UpVecW.Z * fy);
  310. result := sqrt(xx * xx + yy * yy + zz * zz) * dst;
  311. end
  312. else
  313. result := 0;
  314. end;
  315. end;
  316. procedure TgxZBuffer.Refresh;
  317. begin
  318. if assigned(Buffer) then
  319. GetDepthBuffer(True, False);
  320. end;
  321. procedure TgxZBuffer.DoCalcVectors;
  322. var
  323. axs: TAffineVector;
  324. Hnorm, hcvec: TVector4f;
  325. vec: TAffineVector;
  326. w, h: integer;
  327. wrp: single;
  328. begin
  329. if not (assigned(Buffer) and Buffer.RCInstantiated) then
  330. exit;
  331. if not assigned(cam) then
  332. raise EZBufferException.Create('No Camera!');
  333. //-----------For ScreenToVector-------------
  334. w := FWidth;
  335. h := FHeight;
  336. setVector(vec, 0, 0, 0);
  337. lb := buffer.ScreenToVector(vec); // same as cvec...optimise?
  338. setVector(vec, w, 0, 0);
  339. rb := buffer.ScreenToVector(vec);
  340. setVector(vec, 0, h, 0);
  341. lt := buffer.ScreenToVector(vec);
  342. setVector(vec, w, h, 0);
  343. rt := buffer.ScreenToVector(vec);
  344. //------------Set Camera values-------------
  345. normal := VectorLerp(lb, rt, 0.5);
  346. upVec := VectorSubtract(lt, lb);
  347. riVec := VectorSubtract(rb, lb);
  348. // cam:=viewer.Camera;
  349. dov := Cam.DepthOfView;
  350. np := Cam.NearPlane;
  351. fp := Cam.NearPlane + dov;
  352. NpFp := np * fp;
  353. OneMinNp_Fp := 1 - np / fp;
  354. invOneMinNp_Fp := 1 / OneMinNp_Fp;
  355. //-----------For VectorToScreen-------------
  356. (*
  357. cam :=Viewer.Camera.Position.AsAffineVector;
  358. targ:=Viewer.Camera.TargetObject.Position.AsAffineVector;
  359. norm:=VectorSubtract(targ,cam); //---Camera Normal vector---
  360. MakeVector(hnorm,norm);
  361. *)
  362. MakeVector(hnorm, normal);
  363. MakeVector(hcVec, lb); //---Corner Vector---
  364. ang1 := ArcTan2(Hnorm.X, Hnorm.Z);
  365. SetVector(axs, 0, 1, 0);
  366. RotateVector(hnorm, axs, ang1);
  367. RotateVector(hcvec, axs, ang1);
  368. ang2 := ArcTan2(Hnorm.Y, Hnorm.Z);
  369. SetVector(axs, 1, 0, 0);
  370. RotateVector(hcvec, axs, -ang2);
  371. hcvec.X := hcvec.X / hcvec.Z;
  372. vw := Fwidth / 2;
  373. vh := Fheight / 2;
  374. scal := vw / hcvec.X;
  375. SinCosine(-ang1, s1, c1);
  376. SinCosine(-ang2, s2, c2);
  377. //------------------------------------------
  378. //--------------------2-----------------
  379. vec := self.FastScreenToVector(0, 1);
  380. wrp := VectorAngleCosine(normal, vec);
  381. ltW := VectorNormalize(lt);
  382. rtW := VectorNormalize(rt);
  383. lbW := VectorNormalize(lb);
  384. rbW := VectorNormalize(rb);
  385. ltW := VectorScale(ltW, 1 / wrp);
  386. rtW := VectorScale(rtW, 1 / wrp);
  387. lbW := VectorScale(lbW, 1 / wrp);
  388. rbW := VectorScale(rbW, 1 / wrp);
  389. upVecW := VectorSubtract(ltW, lbW);
  390. upVecW := VectorScale(upVecW, 1 / Fheight);
  391. riVecW := VectorSubtract(rbW, lbW);
  392. riVecW := VectorScale(riVecW, 1 / Fwidth);
  393. // UpVecW[0]:=-UpVecW[0];
  394. // UpVecW[1]:=-UpVecW[1];
  395. // UpVecW[2]:=-UpVecW[2];
  396. //--------------------------------------
  397. //-------orth---------
  398. // OrthAdd:=2;
  399. // OrthMul:=64;
  400. orthAddX := rt.X;
  401. OrthMulX := FWidth / (OrthAddX * 2);
  402. orthAddY := rt.Z;
  403. OrthMulY := FHeight / (OrthAddY * 2);
  404. OrthInvDov := 1 / dov;
  405. //--------------------
  406. end;
  407. function TgxZBuffer.FastScreenToVector(x, y: integer): TAffineVector;
  408. var
  409. w, h: integer;
  410. Rlerp, Ulerp: single;
  411. begin
  412. w := FWidth;
  413. h := FHeight;
  414. Rlerp := x / w;
  415. Ulerp := (h - y) / h;
  416. result.X := lb.X + riVec.X * Rlerp + UpVec.X * Ulerp;
  417. result.Y := lb.Y + riVec.Y * Rlerp + UpVec.Y * Ulerp;
  418. result.Z := lb.Z + riVec.Z * Rlerp + UpVec.Z * Ulerp;
  419. end;
  420. function TgxZBuffer.FastVectorToScreen(Vec: TAffineVector): TAffineVector;
  421. var
  422. v0, v1, x, y, z: Single;
  423. begin
  424. x := vec.X;
  425. y := vec.Y;
  426. z := vec.Z;
  427. v0 := x;
  428. x := c1 * v0 + s1 * z;
  429. z := c1 * z - s1 * v0; //Rotate around Y-axis
  430. v1 := y;
  431. y := c2 * v1 + s2 * z;
  432. z := c2 * z - s2 * v1; //Rotate around X-axis
  433. Result.X := Round(-x / z * scal + vw);
  434. Result.Y := Round(y / z * scal + vh);
  435. end;
  436. function TgxZBuffer.PixelToWorld(const x, y: Integer): TAffineVector;
  437. var
  438. z, dst: single;
  439. fy: integer;
  440. camvec: TVector4f;
  441. begin
  442. // if (Cardinal(x)<Cardinal(FWidth)) and (Cardinal(y)<Cardinal(FWidth)) then begin //xres,yres?
  443. if (x < FWidth) and (y < FHeight) then
  444. begin
  445. z := FDataInvIdx[y]^[x];
  446. dst := (NpFp) / (fp - z * dov); //calc from z-buffer value to frustrum depth
  447. camvec := cam.AbsolutePosition;
  448. fy := FHeight - y;
  449. result.X := (lbW.X + riVecW.X * x + UpVecW.X * fy) * dst + camvec.X;
  450. result.Y := (lbW.Y + riVecW.Y * x + UpVecW.Y * fy) * dst + camvec.Y;
  451. result.Z := (lbW.Z + riVecW.Z * x + UpVecW.Z * fy) * dst + camvec.Z;
  452. end
  453. else
  454. begin
  455. result.X := 0;
  456. result.Y := 0;
  457. result.Z := 0;
  458. end;
  459. end;
  460. function TgxZBuffer.WorldToPixel(const aPoint: TAffineVector; out pixX, pixY:
  461. integer; out pixZ: single): boolean;
  462. var
  463. camPos: TVector4f;
  464. x, y, z, v0, v1, zscal: single;
  465. begin
  466. //---Takes x,y,z world coordinate.
  467. //---Result is true if pixel lies within view frustrum
  468. //---returns canvas pixel x,y coordinate, and the world distance
  469. result := false;
  470. campos := cam.AbsolutePosition;
  471. x := apoint.X - camPos.X;
  472. y := apoint.Y - camPos.Y;
  473. z := apoint.Z - camPos.Z; //get vector from camera to world point
  474. v0 := x;
  475. x := c1 * v0 + s1 * z;
  476. z := c1 * z - s1 * v0; //Rotate around Y-axis
  477. v1 := y;
  478. y := c2 * v1 + s2 * z;
  479. z := c2 * z - s2 * v1; //Rotate around X-axis
  480. if z > 0 then
  481. begin
  482. zscal := scal / z;
  483. pixX := Round(-x * zscal + vw);
  484. pixY := Round(y * zscal + vh);
  485. pixZ := sqrt(x * x + y * y + z * z);
  486. if (pixX >= 0) and (pixX < FWidth) and (pixY >= 0) and (pixY < FHeight) then
  487. Result := true;
  488. end
  489. else
  490. begin //ignore anything that is behind the camera
  491. pixX := 0;
  492. pixY := 0;
  493. pixZ := 0;
  494. end;
  495. end;
  496. function TgxZBuffer.WorldToPixelZ(const aPoint: TAffineVector; out pixX, pixY:
  497. integer; out pixZ: single): boolean; //OVERLOAD
  498. var
  499. camPos: TVector4f;
  500. x, y, z, v0, v1, zscal: single;
  501. begin
  502. //---Takes x,y,z world coordinate.
  503. //---Result is true if pixel lies within view frustrum
  504. //---returns canvas pixel x,y coordinate, and CALCULATES the z-buffer distance
  505. campos := cam.AbsolutePosition;
  506. x := apoint.X - camPos.X;
  507. y := apoint.Y - camPos.Y;
  508. z := apoint.Z - camPos.Z; //get vector from camera to world point
  509. v0 := x;
  510. x := c1 * v0 + s1 * z;
  511. z := c1 * z - s1 * v0; //Rotate around Y-axis
  512. v1 := y;
  513. y := c2 * v1 + s2 * z;
  514. z := c2 * z - s2 * v1; //Rotate around X-axis
  515. if z > 0 then
  516. begin
  517. zscal := scal / z;
  518. pixX := Round(-x * zscal + vw);
  519. pixY := Round(y * zscal + vh);
  520. //------z:=(1-np/z)/(1-np/fp);------
  521. // pixZ:=(1-np/z)/(1-np/fp);
  522. pixZ := (1 - np / z) * invOneMinNp_Fp;
  523. Result := (Cardinal(pixX) < Cardinal(FWidth)) and (Cardinal(pixY) <
  524. Cardinal(FHeight));
  525. end
  526. else
  527. begin //ignore anything that is behind the camera
  528. Result := false;
  529. pixX := 0;
  530. pixY := 0;
  531. pixZ := 0;
  532. end;
  533. end;
  534. function TgxZBuffer.WorldToPixelZ(const aPoint: TAffineVector; out pixX, pixY:
  535. single; out pixZ: single): boolean; //OVERLOAD
  536. var
  537. camPos: TVector4f;
  538. x, y, z, invZ, v0, v1, zscal: single;
  539. begin
  540. //---Takes x,y,z world coordinate. (aPoint)
  541. //---Result is true if pixel lies within view frustrum
  542. //---returns canvas pixel x,y coordinate, and CALCULATES the z-buffer distance
  543. campos := cam.AbsolutePosition;
  544. x := apoint.X - camPos.X;
  545. y := apoint.Y - camPos.Y;
  546. z := apoint.Z - camPos.Z; //get vector from camera to world point
  547. v0 := x;
  548. x := c1 * v0 + s1 * z;
  549. z := c1 * z - s1 * v0; //Rotate around Y-axis
  550. v1 := y;
  551. y := c2 * v1 + s2 * z;
  552. z := c2 * z - s2 * v1; //Rotate around X-axis
  553. if z > 0 then
  554. begin
  555. invZ := 1 / z;
  556. zscal := scal * invZ;
  557. pixX := vw - x * zscal;
  558. pixY := vh + y * zscal;
  559. //------z:=(1-np/z)/(1-np/fp);------
  560. // pixZ:=(1-np/z)/(1-np/fp);
  561. pixZ := (1 - np * invZ) * invOneMinNp_Fp;
  562. Result := (pixX >= 0) and (pixX < FWidth) and (pixY >= 0) and (pixY <
  563. FHeight);
  564. end
  565. else
  566. begin //ignore anything that is behind the camera
  567. result := false;
  568. pixX := 0;
  569. pixY := 0;
  570. pixZ := 0;
  571. end;
  572. end;
  573. function TgxZBuffer.OrthWorldToPixelZ(const aPoint: TAffineVector; out pixX,
  574. pixY: single; out pixZ: single): boolean;
  575. var
  576. camPos: TVector4f;
  577. x, y, z: single;
  578. begin
  579. campos := cam.AbsolutePosition;
  580. x := apoint.X - camPos.X;
  581. y := apoint.Y - camPos.Y;
  582. z := apoint.Z - camPos.Z; //get vector from camera to world point
  583. pixX := (x + OrthAddX) * OrthMulX;
  584. pixY := (z + OrthAddY) * OrthMulY;
  585. pixZ := (-y - np) * OrthInvDov; //(-y-np)/dov
  586. Result := (pixX >= 0) and (pixX < FWidth) and (pixY >= 0) and (pixY <
  587. FHeight);
  588. end;
  589. // ------------------
  590. // ------------------ TgxZShadows ------------------
  591. // ------------------
  592. constructor TgxZShadows.Create(AOwner: TComponent);
  593. begin
  594. inherited;
  595. ObjectStyle := ObjectStyle + [osDirectDraw, osNoVisibilityCulling];
  596. FColor := TgxColor.Create(Self);
  597. self.FDataSize := 0;
  598. self.FXRes := 64;
  599. self.FYRes := 64;
  600. self.Tolerance := 0.015;
  601. FTexHandle := TgxTextureHandle.Create;
  602. end;
  603. destructor TgxZShadows.Destroy;
  604. begin
  605. ViewerZBuf.Free;
  606. CasterZBuf.Free;
  607. FColor.Free;
  608. FTexHandle.Free;
  609. FreeMem(FData);
  610. inherited Destroy;
  611. end;
  612. procedure TgxZShadows.BindTexture;
  613. begin
  614. if FTexHandle.Handle = 0 then
  615. with FTexHandle do
  616. begin
  617. AllocateHandle;
  618. with RenderingContext.gxStates do
  619. begin
  620. TextureBinding[0, ttTexture2D] := Handle;
  621. glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_Fastest);
  622. UnpackAlignment := 1;
  623. UnpackRowLength := 0;
  624. UnpackSkipRows := 0;
  625. UnpackSkipPixels := 0;
  626. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  627. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  628. ActiveTextureEnabled[ttTexture2D] := True;
  629. SetBlendFunc(bfSRCALPHA, bfONEMINUSSRCALPHA);
  630. glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  631. Enable(stBlend);
  632. PrepareAlphaMemory;
  633. end;
  634. end
  635. else
  636. with FTexHandle do
  637. RenderingContext.gxStates.TextureBinding[0, ttTexture2D] := Handle;
  638. end;
  639. procedure TgxZShadows.PrepareAlphaMemory;
  640. var
  641. i: Integer;
  642. begin
  643. // ShowMessage(IntToStr(FWidth)+' '+IntToStr(FXRes));
  644. FDataSize := FXRes * FYRes * 1;
  645. ReallocMem(FData, FDataSize);
  646. SetLength(FDataIdx, FYRes);
  647. SetLength(FDataInvIdx, FYRes);
  648. for i := 0 to FYres - 1 do
  649. begin
  650. FDataIdx[i] := @FData[i * FXRes]; // range: [0..height-1]
  651. FDataInvIdx[i] := @FData[(FYRes - i - 1) * FXRes]; // range: [0..height-1]
  652. end;
  653. end;
  654. procedure TgxZShadows.DoRender(var ARci: TgxRenderContextInfo;
  655. ARenderSelf, ARenderChildren: Boolean);
  656. var
  657. vx, vy, vx1, vy1: Single;
  658. xtex, ytex: single;
  659. begin
  660. if not assigned(FViewer) then
  661. exit;
  662. if not assigned(FCaster) then
  663. exit;
  664. if not assigned(CasterZBuf) then
  665. exit; //only render if a shadow has been cast
  666. //only render in view-camera
  667. if TgxSceneBuffer(ARci.buffer).Camera <> FViewer.Camera then
  668. exit;
  669. if not assigned(ViewerZBuf) then
  670. begin //Create viewer zbuffer
  671. ViewerZBuf := TgxZBuffer.Create;
  672. ViewerZBuf.LinkToViewer(FViewer);
  673. Bindtexture;
  674. FTexturePrepared := False;
  675. end;
  676. ViewerZBuf.Refresh;
  677. ARci.gxStates.ActiveTextureEnabled[ttTexture2D] := True;
  678. ARci.gxStates.Enable(stBlend);
  679. ARci.gxStates.SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
  680. if FWidth > ARci.viewPortSize.cx then
  681. Fwidth := ARci.viewPortSize.cx;
  682. if FHeight > ARci.viewPortSize.cy then
  683. FHeight := ARci.viewPortSize.cy;
  684. //-----------------------
  685. CalcShadowTexture(ARci);
  686. //-----------------------
  687. ARci.gxStates.TextureBinding[0, ttTexture2D] := FTexHandle.Handle;
  688. //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
  689. glColor3f(SCol.r, SCol.g, SCol.b);
  690. if not FTexturePrepared then
  691. begin
  692. glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, FXRes, FYRes, 0, GL_ALPHA,
  693. GL_UNSIGNED_BYTE, @FData[0]);
  694. FTexturePrepared := True;
  695. end
  696. else
  697. glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, FXRes, FYRes, GL_ALPHA,
  698. GL_UNSIGNED_BYTE, @FData[0]);
  699. // NotifyChange(Self);
  700. //>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
  701. // Prepare matrices
  702. glMatrixMode(GL_MODELVIEW);
  703. glPushMatrix;
  704. glLoadMatrixf(@TgxSceneBuffer(ARci.buffer).BaseProjectionMatrix);
  705. glScalef(2 / ARci.viewPortSize.cx, 2 / ARci.viewPortSize.cy, 1);
  706. glTranslatef(Position.X - ARci.viewPortSize.cx * 0.5,
  707. ARci.viewPortSize.cy * 0.5 - Position.Y, Position.Z);
  708. glMatrixMode(GL_PROJECTION);
  709. glPushMatrix;
  710. glLoadIdentity;
  711. ARci.gxStates.Disable(stDepthTest);
  712. ARci.gxStates.Disable(stLighting);
  713. vx := 0;
  714. vx1 := vx + FWidth;
  715. vy := 0;
  716. vy1 := vy - FHeight;
  717. Xtex := FWidth / FXres; //1
  718. Ytex := 1 - (FHeight / FYres); //0
  719. // issue quad
  720. glBegin(GL_QUADS);
  721. glNormal3fv(@YVector);
  722. glTexCoord2f(0, ytex);
  723. glVertex2f(vx, vy1);
  724. glTexCoord2f(xtex, ytex);
  725. glVertex2f(vx1, vy1);
  726. glTexCoord2f(xtex, 1);
  727. glVertex2f(vx1, vy);
  728. glTexCoord2f(0, 1);
  729. glVertex2f(vx, vy);
  730. glEnd;
  731. // restore state
  732. glPopMatrix;
  733. glMatrixMode(GL_MODELVIEW);
  734. glPopMatrix;
  735. if Count > 0 then
  736. Self.RenderChildren(0, Count - 1, ARci);
  737. end;
  738. procedure TgxZShadows.CalcShadowTexture(var rci: TgxRenderContextInfo);
  739. var
  740. pix, p0, p1, p2, p3, p4: Byte;
  741. pM, pL, pT: Byte;
  742. pixa: PAArray;
  743. x, y, w, h: integer;
  744. xy: integer;
  745. begin
  746. pixa := FData;
  747. w := fXres;
  748. h := fYres;
  749. SCol.r := Round(FColor.Red * 255);
  750. SCol.g := Round(FColor.green * 255);
  751. SCol.b := Round(FColor.Blue * 255);
  752. SCol.a := Round(FColor.Alpha * 255);
  753. //-----------No optimising-----------
  754. if FOptimise = opNone then
  755. begin
  756. y := 0;
  757. while y < FHeight do
  758. begin
  759. x := 0;
  760. while x < fWidth do
  761. begin
  762. HardSet(x, y);
  763. x := x + 1;
  764. end;
  765. y := y + 1;
  766. end;
  767. end
  768. else
  769. if FOptimise = op4in1 then
  770. begin
  771. for x := 0 to fXres - 1 do
  772. HardSet(x, 0);
  773. for x := 0 to fXres - 1 do
  774. HardSet(x, fYres - 1);
  775. for y := 1 to fYres - 1 do
  776. HardSet(0, y);
  777. for y := 1 to fYres - 1 do
  778. HardSet(fXres - 1, y);
  779. y := 2;
  780. while y < fYres do
  781. begin
  782. x := 2;
  783. p1 := HardSet(x - 1, y - 2);
  784. HardSet(x - 1, y - 1);
  785. p0 := HardSet(x - 1, y);
  786. while x < fXres do
  787. begin
  788. pix := HardSet(x, y);
  789. if (pix = p1) and (pix = p0) then
  790. begin
  791. FDataInvIdx[y]^[x - 1] := pix;
  792. FDataInvIdx[y - 1]^[x - 1] := pix;
  793. end
  794. else
  795. begin
  796. HardSet(x - 1, y);
  797. HardSet(x - 1, y - 1);
  798. end;
  799. p2 := SoftTest(x + 1, y - 2);
  800. if (pix = p2) then
  801. FDataInvIdx[y - 1]^[x] := pix
  802. else
  803. HardSet(x, y - 1);
  804. p1 := p2;
  805. p0 := pix;
  806. x := x + 2;
  807. end;
  808. y := y + 2;
  809. end;
  810. end
  811. else
  812. if FOptimise = op9in1 then
  813. begin
  814. for x := 0 to fXres - 1 do
  815. HardSet(x, 0);
  816. for x := 0 to fXres - 1 do
  817. HardSet(x, fYres - 1);
  818. for y := 0 to fYres - 1 do
  819. HardSet(fXres - 1, y);
  820. // for y:=1 to fYres-1 do HardSet(fXres-2,y);
  821. y := 3;
  822. while y < fYres do
  823. begin
  824. x := 3;
  825. p1 := HardSet(x - 3, y - 3);
  826. // p2:=HardSet(x ,y-3);
  827. p3 := HardSet(x - 3, y);
  828. while x < fXres do
  829. begin
  830. p2 := SoftTest(x, y - 3);
  831. p4 := HardSet(x, y);
  832. if ((p1 = p2) and (p3 = p4) and (p2 = p4)) then
  833. begin
  834. xy := x + (fYres - (y - 3) - 1) * fXres;
  835. pixa^[xy - 2] := p4;
  836. pixa^[xy - 1] := p4;
  837. xy := xy - w; //xy:=x+(fYres-(y-2)-1)*fXres;
  838. pixa^[xy - 3] := p4;
  839. pixa^[xy - 2] := p4;
  840. pixa^[xy - 1] := p4;
  841. xy := xy - w; //xy:=x+(fYres-(y-1)-1)*fXres;
  842. pixa^[xy - 3] := p4;
  843. pixa^[xy - 2] := p4;
  844. pixa^[xy - 1] := p4;
  845. end
  846. else
  847. begin
  848. HardSet(x - 2, y - 3);
  849. HardSet(x - 1, y - 3);
  850. HardSet(x - 3, y - 2);
  851. HardSet(x - 2, y - 2);
  852. HardSet(x - 1, y - 2);
  853. HardSet(x - 3, y - 1);
  854. HardSet(x - 2, y - 1);
  855. HardSet(x - 1, y - 1);
  856. end;
  857. p1 := p2;
  858. p3 := p4;
  859. x := x + 3;
  860. end;
  861. y := y + 3;
  862. end;
  863. end
  864. else
  865. if FOptimise = op16in1 then
  866. begin
  867. y := 4;
  868. while (y <> FHeight + 3) do
  869. begin
  870. if y >= FHeight then
  871. y := FHeight - 1;
  872. repeat
  873. x := 4;
  874. p1 := HardSet(x - 4, y - 4);
  875. // HardSet(x ,y-4); //p2
  876. p3 := HardSet(x - 4, y);
  877. while (x <> fWidth + 3) do
  878. begin
  879. if x >= FWidth then
  880. x := FWidth - 1;
  881. repeat
  882. p2 := SoftTest(x, y - 4);
  883. p4 := HardSet(x, y);
  884. //p4.r:=255;
  885. if ((p1 = p2) and (p3 = p4) and (p2 = p4)) then
  886. begin
  887. xy := x + (h - (y - 4) - 1) * w;
  888. pixa^[xy - 3] := p4;
  889. pixa^[xy - 2] := p4;
  890. pixa^[xy - 1] := p4;
  891. xy := xy - w;
  892. pixa^[xy - 4] := p4;
  893. pixa^[xy - 3] := p4;
  894. pixa^[xy - 2] := p4;
  895. pixa^[xy - 1] := p4;
  896. xy := xy - w;
  897. pixa^[xy - 4] := p4;
  898. pixa^[xy - 3] := p4;
  899. pixa^[xy - 2] := p4;
  900. pixa^[xy - 1] := p4;
  901. xy := xy - w;
  902. pixa^[xy - 4] := p4;
  903. pixa^[xy - 3] := p4;
  904. pixa^[xy - 2] := p4;
  905. pixa^[xy - 1] := p4;
  906. end
  907. else
  908. begin
  909. //--------------------------------------------
  910. pM := HardSet(x - 2, y - 2);
  911. pL := HardSet(x - 4, y - 2);
  912. pT := HardSet(x - 2, y - 4);
  913. xy := x + (h - (y - 4) - 1) * w;
  914. if (p1 = pT) then
  915. pixa^[xy - 3] := pT
  916. else
  917. HardSet(x - 3, y - 4);
  918. if (p2 = pT) then
  919. pixa^[xy - 1] := pT
  920. else
  921. HardSet(x - 1, y - 4);
  922. xy := xy - w; //down
  923. if (pL = p1) then
  924. pixa^[xy - 4] := pL
  925. else
  926. HardSet(x - 4, y - 3);
  927. if (p1 = pM) then
  928. pixa^[xy - 3] := pM
  929. else
  930. HardSet(x - 3, y - 3);
  931. if (p2 = pM) then
  932. pixa^[xy - 1] := pM
  933. else
  934. HardSet(x - 1, y - 3); //p2m
  935. if (pT = pM) then
  936. pixa^[xy - 2] := pM
  937. else
  938. HardSet(x - 2, y - 3);
  939. xy := xy - w; //down
  940. if (pL = pM) then
  941. pixa^[xy - 3] := pM
  942. else
  943. HardSet(x - 3, y - 2);
  944. xy := xy - w; //down
  945. if (p3 = pL) then
  946. pixa^[xy - 4] := pL
  947. else
  948. HardSet(x - 4, y - 1);
  949. if (p3 = pM) then
  950. pixa^[xy - 3] := pM
  951. else
  952. HardSet(x - 3, y - 1); //p3m
  953. if (p4 = pM) then
  954. begin
  955. pixa^[xy - 1] := pM;
  956. if (pM = p2) then
  957. pixa^[xy + w - 1] := pM
  958. else
  959. HardSet(x - 1, y - 2);
  960. if (pM = p3) then
  961. pixa^[xy - 2] := pM
  962. else
  963. HardSet(x - 2, y - 1);
  964. end
  965. else
  966. begin
  967. HardSet(x - 1, y - 1); //p4m
  968. HardSet(x - 1, y - 2);
  969. HardSet(x - 2, y - 1);
  970. end;
  971. end;
  972. p1 := p2;
  973. p3 := p4;
  974. x := x + 4;
  975. until x >= FWidth;
  976. end; //while
  977. y := y + 4;
  978. until y > (FHeight - 2);
  979. end; //while
  980. for x := 0 to FWidth - 1 do
  981. FDataIdx[0][x] := FDataIdx[1][x];
  982. for y := 0 to FHeight - 1 do
  983. FDataIdx[y][FWidth - 1] := FDataIdx[y][FWidth - 2];
  984. end;
  985. end;
  986. //--------------------------------------------------------------------
  987. function TgxZShadows.HardSet(const x, y: integer): Byte;
  988. var
  989. pix: Byte;
  990. coord: TAffineVector;
  991. ipixX, ipixY: integer;
  992. pixX, pixY: single;
  993. pixZ: single;
  994. IsInFrust: Boolean;
  995. ilum: Integer;
  996. shad: single;
  997. Tol: Single;
  998. modx, mody: single;
  999. d2, d4, d5, d6, d8: single;
  1000. shad2, shad4, shad5, shad6, shad8: single;
  1001. function ComputeIlum: Integer;
  1002. begin
  1003. //---Lighting---
  1004. if FDepthFade = True then
  1005. begin
  1006. Result := Round(SCol.a * (pixZ * 10 - 9));
  1007. if Result < 0 then
  1008. Result := 0;
  1009. //if ilum>255 then ilum:=255;
  1010. if Result > SCol.a then
  1011. Result := SCol.a;
  1012. end
  1013. else
  1014. Result := 0;
  1015. end;
  1016. begin
  1017. //---test pixel for shadow---
  1018. if ViewerZBuf.GetPixelzDepth(x, y) < 1 then
  1019. begin
  1020. coord := ViewerZBuf.PixelToWorld(x, y);
  1021. IsInFrust := CasterZBuf.WorldToPixelZ(coord, pixX, pixY, pixZ);
  1022. //if caster.Camera.CameraStyle=csOrthogonal then IsInFrust:=CasterZBuf.OrthWorldToPixelZ(coord,pixX,pixY,pixZ);
  1023. //--- Tolerance scaling - reduces shadow-creeping at long-range and self-shadowing at short-range ---
  1024. tol := FTolerance * (1.0 - pixZ);
  1025. //--- ilum=light ------ SCol.a=shade ------
  1026. if not isInFrust then
  1027. begin
  1028. if FFrustShadow then
  1029. pix := SCol.a //dark outside frustrum
  1030. else
  1031. pix := ComputeIlum; //light outside frustrum
  1032. end
  1033. else
  1034. begin
  1035. ipixX := Trunc(pixX);
  1036. ipixY := Trunc(pixY);
  1037. if (FSoft = True) and (ipixY > 0) then
  1038. begin //---soft shadows---
  1039. modx := Frac(pixX);
  1040. //extract the fraction part only - used to interpolate soft shadow edges
  1041. mody := Frac(pixY);
  1042. if ipixX > 0 then
  1043. d4 := CasterZBuf.DataIdx[ipixY]^[ipixX - 1]
  1044. else
  1045. d4 := CasterZBuf.DataIdx[ipixY]^[0];
  1046. d5 := CasterZBuf.DataIdx[ipixY]^[ipixX];
  1047. d6 := CasterZBuf.DataIdx[ipixY]^[ipixX + 1];
  1048. d8 := CasterZBuf.DataIdx[ipixY + 1]^[ipixX];
  1049. // if ipixY<1 then d2:=d5 else
  1050. d2 := CasterZBuf.DataIdx[ipixY - 1]^[ipixX];
  1051. ilum := ComputeIlum;
  1052. if ((pixZ - d2) > Tol) then
  1053. Shad2 := SCol.a
  1054. else
  1055. Shad2 := ilum;
  1056. if ((pixZ - d4) > Tol) then
  1057. Shad4 := SCol.a
  1058. else
  1059. Shad4 := ilum;
  1060. if ((pixZ - d5) > Tol) then
  1061. Shad5 := SCol.a
  1062. else
  1063. Shad5 := ilum;
  1064. if ((pixZ - d6) > Tol) then
  1065. Shad6 := SCol.a
  1066. else
  1067. Shad6 := ilum;
  1068. if ((pixZ - d8) > Tol) then
  1069. Shad8 := SCol.a
  1070. else
  1071. Shad8 := ilum;
  1072. shad := shad2 + (shad8 - shad2) * mody +
  1073. shad4 + (shad6 - shad4) * modx + shad5;
  1074. pix := Round(Shad / 3);
  1075. end
  1076. else
  1077. begin //---hard shadows---
  1078. if pixZ - Tol > CasterZBuf.DataIdx[ipixY]^[ipixX] then
  1079. pix := SCol.a //dark
  1080. else
  1081. pix := ComputeIlum; //light
  1082. end;
  1083. end;
  1084. end
  1085. else
  1086. begin // if z=1 ... i.e. nothing was drawn at this pixel (sky)
  1087. if FSkyShadow then
  1088. pix := SCol.a // dark
  1089. else
  1090. pix := 0; //ComputeIlum; // light
  1091. end;
  1092. FDataInvIdx[y]^[x] := pix; //Write pixel
  1093. result := pix;
  1094. end;
  1095. function TgxZShadows.SoftTest(const x, y: integer): Byte;
  1096. begin
  1097. result := FDataInvIdx[y]^[x];
  1098. end;
  1099. function TgxZShadows.GetViewer: TgxSceneViewer;
  1100. begin
  1101. result := FViewer;
  1102. end;
  1103. procedure TgxZShadows.SetViewer(const val: TgxSceneViewer);
  1104. begin
  1105. FViewer := Val;
  1106. Width := FViewer.Buffer.Width;
  1107. Height := FViewer.Buffer.Height;
  1108. end;
  1109. function TgxZShadows.GetCaster: TgxMemoryViewer;
  1110. begin
  1111. result := FCaster;
  1112. end;
  1113. procedure TgxZShadows.SetCaster(const val: TgxMemoryViewer);
  1114. begin
  1115. FCaster := Val;
  1116. end;
  1117. function TgxZShadows.CastShadow: Boolean;
  1118. begin
  1119. if Caster <> nil then
  1120. begin
  1121. if not assigned(CasterZBuf) then
  1122. begin
  1123. CasterZBuf := TgxZBuffer.Create;
  1124. CasterZBuf.LinkToViewer(FCaster);
  1125. end;
  1126. if FCaster.Camera.CameraStyle = csOrthogonal then
  1127. begin
  1128. if assigned(FCaster.Camera.TargetObject) then
  1129. begin
  1130. FCaster.Camera.Position.x := FCaster.Camera.TargetObject.Position.x;
  1131. FCaster.Camera.Position.z := FCaster.Camera.TargetObject.Position.z;
  1132. end;
  1133. with FCaster.Camera.direction do
  1134. begin
  1135. x := 0;
  1136. y := -1;
  1137. z := 0;
  1138. end;
  1139. end;
  1140. try
  1141. FCaster.Render;
  1142. except
  1143. Caster := nil; // prevents further attempts
  1144. raise;
  1145. end;
  1146. CasterZBuf.Refresh;
  1147. Result := False;
  1148. end
  1149. else
  1150. Result := True;
  1151. end;
  1152. procedure TgxZShadows.SetWidth(const val: integer);
  1153. begin
  1154. FWidth := val;
  1155. SetXRes(val);
  1156. end;
  1157. procedure TgxZShadows.SetHeight(const val: integer);
  1158. begin
  1159. FHeight := val;
  1160. SetYRes(val);
  1161. end;
  1162. procedure TgxZShadows.SetXRes(const val: integer);
  1163. var
  1164. i: integer;
  1165. begin
  1166. i := 2;
  1167. while val > i do
  1168. i := i * 2; //
  1169. FXRes := i; //calculate the closest power of 2, smaller than val
  1170. FTexturePrepared := False;
  1171. PrepareAlphaMemory;
  1172. end;
  1173. procedure TgxZShadows.SetYRes(const val: integer);
  1174. var
  1175. i: integer;
  1176. begin
  1177. i := 2;
  1178. while val > i do
  1179. i := i * 2; //
  1180. FYRes := i; //calculate the closest power of 2, larger than val
  1181. FTexturePrepared := False;
  1182. PrepareAlphaMemory;
  1183. end;
  1184. procedure TgxZShadows.SetSoft(const val: boolean);
  1185. begin
  1186. FSoft := val;
  1187. NotifyChange(Self);
  1188. end;
  1189. // ------------------------------------------------------------------
  1190. initialization
  1191. // ------------------------------------------------------------------
  1192. RegisterClasses([TgxZShadows]);
  1193. end.