GLS.HeightData.pas 59 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967
  1. //
  2. // The multimedia graphics platform GLScene https://github.com/glscene
  3. //
  4. unit GLS.HeightData;
  5. (*
  6. Classes for height data access.
  7. The components and classes in the unit are the core data providers for
  8. height-based objects (terrain rendering mainly), they are independant
  9. from the rendering stage.
  10. In short: access to raw height data is performed by a TGLHeightDataSource
  11. subclass, that must take care of performing all necessary data access,
  12. cacheing and manipulation to provide TGLHeightData objects. A TGLHeightData
  13. is basicly a square, power of two dimensionned raster heightfield, and
  14. holds the data a renderer needs.
  15. *)
  16. interface
  17. {$I GLScene.inc}
  18. uses
  19. Winapi.Windows, // to CreateMonochromeBitmap
  20. System.Classes,
  21. System.SysUtils,
  22. System.Types,
  23. Vcl.Graphics,
  24. GLS.ApplicationFileIO,
  25. GLS.Utils,
  26. GLS.VectorGeometry,
  27. GLS.Material,
  28. GLS.BaseClasses;
  29. type
  30. TByteArray = array [0 .. MaxInt div (2 * SizeOf(Byte))] of Byte;
  31. TByteRaster = array [0 .. MaxInt div (2 * SizeOf(Pointer))] of PByteArray;
  32. PByteRaster = ^TByteRaster;
  33. TSmallintArray = array [0 .. MaxInt div (2 * SizeOf(SmallInt))] of SmallInt;
  34. PSmallIntArray = ^TSmallintArray;
  35. TSmallIntRaster = array [0 .. MaxInt div (2 * SizeOf(Pointer))
  36. ] of PSmallIntArray;
  37. PSmallIntRaster = ^TSmallIntRaster;
  38. TSingleRaster = array [0 .. MaxInt div (2 * SizeOf(Pointer))] of PSingleArray;
  39. PSingleRaster = ^TSingleRaster;
  40. TGLHeightData = class;
  41. TGLHeightDataClass = class of TGLHeightData;
  42. (* Determines the type of data stored in a TGLHeightData.
  43. There are 3 data types (8 bits unsigned, signed 16 bits and 32 bits).
  44. Conversions: (128*(ByteValue-128)) = SmallIntValue = Round(SingleValue).
  45. The 'hdtDefault' type is used for request only, and specifies that the
  46. default type for the source should be used. *)
  47. TGLHeightDataType = (hdtByte, hdtSmallInt, hdtSingle, hdtDefault);
  48. (* Base class for height datasources.
  49. This class is abstract and presents the standard interfaces for height
  50. data retrieval (TGLHeightData objects). The class offers the following
  51. features (that a subclass may decide to implement or not, what follow
  52. is the complete feature set, check subclass doc to see what is actually
  53. supported):
  54. Pooling / Cacheing (return a TGLHeightData with its "Release" method)
  55. Pre-loading : specify a list of TGLHeightData you want to preload
  56. Multi-threaded preload/queueing : specified list can be loaded in
  57. a background task. *)
  58. TGLHeightDataSource = class(TComponent)
  59. private
  60. FData: TThreadList; // stores all TGLHeightData, whatever their state/type
  61. FDataHash: array [0 .. 255] of TList; // X/Y hash references for HeightDatas
  62. FThread: TThread; // queue manager
  63. FMaxThreads: Integer;
  64. FMaxPoolSize: Integer;
  65. FHeightDataClass: TGLHeightDataClass;
  66. // FReleaseLatency : TDateTime; //Not used anymore???
  67. FDefaultHeight: Single;
  68. protected
  69. procedure SetMaxThreads(const Val: Integer);
  70. function HashKey(XLeft, YTop: Integer): Integer;
  71. // Adjust this property in you subclasses.
  72. property HeightDataClass: TGLHeightDataClass read FHeightDataClass
  73. write FHeightDataClass;
  74. // Looks up the list and returns the matching TGLHeightData, if any.
  75. function FindMatchInList(XLeft, YTop, size: Integer;
  76. DataType: TGLHeightDataType): TGLHeightData;
  77. public
  78. constructor Create(AOwner: TComponent); override;
  79. destructor Destroy; override;
  80. // Access to currently pooled TGLHeightData objects, and Thread locking
  81. property Data: TThreadList read FData;
  82. (* Empties the Data list, terminating thread if necessary.
  83. If some TGLHeightData are hdsInUse, triggers an exception and does
  84. nothing. *)
  85. procedure Clear;
  86. (* Removes less used TDataHeight objects from the pool.
  87. Only removes objects whose state is hdsReady and UseCounter is zero,
  88. starting from the end of the list until total data size gets below
  89. MaxPoolSize (or nothing can be removed). *)
  90. procedure CleanUp;
  91. (* Base TGLHeightData requester method.
  92. Returns (by rebuilding it or from the cache) a TGLHeightData
  93. corresponding to the given area. Size must be a power of two.
  94. Subclasses may choose to publish it or just publish datasource-
  95. specific requester method using specific parameters. *)
  96. function GetData(XLeft, YTop, size: Integer; DataType: TGLHeightDataType)
  97. : TGLHeightData; virtual;
  98. // Preloading request. See GetData for details.
  99. function PreLoad(XLeft, YTop, size: Integer; DataType: TGLHeightDataType)
  100. : TGLHeightData; virtual;
  101. // Replacing dirty tiles.
  102. procedure PreloadReplacement(aHeightData: TGLHeightData);
  103. (* Notification that the data is no longer used by the renderer.
  104. Default behaviour is just to change DataState to hdsReady (ie. return
  105. the data to the pool) *)
  106. procedure Release(aHeightData: TGLHeightData); virtual;
  107. (* Marks the given area as "dirty" (ie source data changed).
  108. All loaded and in-cache tiles overlapping the area are flushed. *)
  109. procedure MarkDirty(const Area: TRect); overload; virtual;
  110. procedure MarkDirty(XLeft, YTop, xRight, yBottom: Integer); overload;
  111. procedure MarkDirty; overload;
  112. (* Maximum number of background threads.
  113. If 0 (zero), multithreading is disabled and StartPreparingData
  114. will be called from the mainthread, and all preload requirements
  115. (queued TGLHeightData objects) will be loaded in sequence from the main thread.
  116. If 1, basic multithreading and queueing gets enabled,
  117. ie. StartPreparingData will be called from a thread, but from one
  118. thread only (ie. there is no need to implement a TGLHeightDataThread,
  119. just make sure StartPreparingData code is thread-safe).
  120. Other values (2 and more) are relevant only if you implement
  121. a TGLHeightDataThread subclass and fire it in StartPreparingData. *)
  122. property MaxThreads: Integer read FMaxThreads write SetMaxThreads;
  123. (* Maximum Size of TDataHeight pool in bytes.
  124. The pool (cache) can actually get larger if more data than the pool
  125. can accomodate is used, but as soon as data gets released and returns
  126. to the pool, TDataHeight will be freed until total pool Size gets
  127. below this figure.
  128. The pool manager frees TDataHeight objects who haven't been requested
  129. for the longest time first.
  130. The default value of zero effectively disables pooling. *)
  131. property MaxPoolSize: Integer read FMaxPoolSize write FMaxPoolSize;
  132. // Height to return for undefined tiles.
  133. property DefaultHeight: Single read FDefaultHeight write FDefaultHeight;
  134. // Interpolates height for the given point.
  135. function InterpolatedHeight(x, y: Single; TileSize: Integer) : Single; virtual;
  136. function Width: Integer; virtual; abstract;
  137. function Height: Integer; virtual; abstract;
  138. procedure ThreadIsIdle; virtual;
  139. // This is called BEFORE StartPreparing Data, but always from the main thread.
  140. procedure BeforePreparingData(HeightData: TGLHeightData); virtual;
  141. (* Request to start preparing data.
  142. If your subclass is thread-enabled, this is here that you'll create
  143. your thread and fire it (don't forget the requirements), if not,
  144. that'll be here you'll be doing your work.
  145. Either way, you are responsible for adjusting the DataState to
  146. hdsReady when you're done (DataState will be hdsPreparing when this
  147. method will be invoked). *)
  148. procedure StartPreparingData(HeightData: TGLHeightData); virtual;
  149. // This is called After "StartPreparingData", but always from the main thread
  150. procedure AfterPreparingData(HeightData: TGLHeightData); virtual;
  151. procedure TextureCoordinates(HeightData: TGLHeightData;
  152. Stretch: boolean = false);
  153. end;
  154. THDTextureCoordinatesMode = (tcmWorld, tcmLocal);
  155. (* Possible states for a TGLHeightData.
  156. hdsQueued : the data has been queued for loading
  157. hdsPreparing : the data is currently loading or being prepared for use
  158. hdsReady : the data is fully loaded and ready for use
  159. hdsNone : the height data does not exist for this tile *)
  160. TGLHeightDataState = (hdsQueued, hdsPreparing, hdsReady, hdsNone);
  161. TGLHeightDataThread = class;
  162. TOnHeightDataDirtyEvent = procedure(sender: TGLHeightData) of object;
  163. TGLHeightDataUser = record
  164. user: TObject;
  165. event: TOnHeightDataDirtyEvent;
  166. end;
  167. (* Base class for height data, stores a height-field raster.
  168. The raster is a square, whose Size must be a power of two. Data can be
  169. accessed through a base pointer ("ByteData[n]" f.i.), or through pointer
  170. indirections ("ByteRaster[y][x]" f.i.), this are the fastest way to access
  171. height data (and the most unsecure).
  172. Secure (with range checking) data access is provided by specialized
  173. methods (f.i. "ByteHeight"), in which coordinates (x & y) are always
  174. considered relative (like in raster access).
  175. The class offers conversion facility between the types (as a whole data
  176. conversion), but in any case, the TGLHeightData should be directly requested
  177. from the TGLHeightDataSource with the appropriate format.
  178. Though this class can be instantiated, you will usually prefer to subclass
  179. it in real-world cases, f.i. to add texturing data. *)
  180. /// TGLHeightData = class (TObject)
  181. TGLHeightData = class(TGLUpdateAbleObject)
  182. private
  183. FUsers: array of TGLHeightDataUser;
  184. FOwner: TGLHeightDataSource;
  185. FDataState: TGLHeightDataState;
  186. FSize: Integer;
  187. FXLeft, FYTop: Integer;
  188. FUseCounter: Integer;
  189. FDataType: TGLHeightDataType;
  190. FDataSize: Integer;
  191. FByteData: PByteArray;
  192. FByteRaster: PByteRaster;
  193. FSmallIntData: PSmallIntArray;
  194. FSmallIntRaster: PSmallIntRaster;
  195. FSingleData: PSingleArray;
  196. FSingleRaster: PSingleRaster;
  197. FTextureCoordinatesMode: THDTextureCoordinatesMode;
  198. FTCOffset, FTCScale: TTexPoint;
  199. FMaterialName: String; // Unsafe. Use FLibMaterial instead
  200. FLibMaterial: TGLLibMaterial;
  201. FObjectTag: TObject;
  202. FTag, FTag2: Integer;
  203. FOnDestroy: TNotifyEvent;
  204. FDirty: boolean;
  205. FHeightMin, FHeightMax: Single;
  206. procedure BuildByteRaster;
  207. procedure BuildSmallIntRaster;
  208. procedure BuildSingleRaster;
  209. procedure ConvertByteToSmallInt;
  210. procedure ConvertByteToSingle;
  211. procedure ConvertSmallIntToByte;
  212. procedure ConvertSmallIntToSingle;
  213. procedure ConvertSingleToByte;
  214. procedure ConvertSingleToSmallInt;
  215. protected
  216. FThread: TGLHeightDataThread;
  217. // thread used for multi-threaded processing (if any)
  218. procedure SetDataType(const Val: TGLHeightDataType);
  219. procedure SetMaterialName(const MaterialName: string);
  220. procedure SetLibMaterial(LibMaterial: TGLLibMaterial);
  221. function GetHeightMin: Single;
  222. function GetHeightMax: Single;
  223. public
  224. OldVersion: TGLHeightData; // previous version of this tile
  225. NewVersion: TGLHeightData; // the replacement tile
  226. DontUse: boolean; // Tells TerrainRenderer which version to use
  227. // constructor Create(AOwner : TComponent); override;
  228. constructor Create(AOwner: TGLHeightDataSource; aXLeft, aYTop, aSize: Integer;
  229. aDataType: TGLHeightDataType); reintroduce; virtual;
  230. destructor Destroy; override;
  231. // The component who created and maintains this data.
  232. property Owner: TGLHeightDataSource read FOwner;
  233. // Fired when the object is destroyed.
  234. property OnDestroy: TNotifyEvent read FOnDestroy write FOnDestroy;
  235. (* Counter for use registration.
  236. A TGLHeightData is not returned to the pool until this counter reaches
  237. a value of zero. *)
  238. property UseCounter: Integer read FUseCounter;
  239. (* Increments UseCounter.
  240. User objects should implement a method that will be notified when
  241. the data becomes dirty, when invoked they should release the heightdata
  242. immediately after performing their own cleanups. *)
  243. procedure RegisterUse;
  244. (* Allocate memory and prepare lookup tables for current datatype.
  245. Fails if already allocated. Made Dynamic to allow descendants *)
  246. procedure Allocate(const Val: TGLHeightDataType); virtual;
  247. (* Decrements UseCounter.
  248. When the counter reaches zero, notifies the Owner TGLHeightDataSource
  249. that the data is no longer used.
  250. The renderer should call Release when it no longer needs a THeighData,
  251. and never free/destroy the object directly. *)
  252. procedure Release;
  253. (* Marks the tile as dirty.
  254. The immediate effect is currently the destruction of the tile. *)
  255. procedure MarkDirty;
  256. (* World X coordinate of top left point. *)
  257. property XLeft: Integer read FXLeft;
  258. (* World Y coordinate of top left point. *)
  259. property YTop: Integer read FYTop;
  260. (* Type of the data.
  261. Assigning a new datatype will result in the data being converted. *)
  262. property DataType: TGLHeightDataType read FDataType write SetDataType;
  263. (* Current state of the data. *)
  264. property DataState: TGLHeightDataState read FDataState write FDataState;
  265. (* Size of the data square, in data units. *)
  266. property Size: Integer read FSize;
  267. (* True if the data is dirty (ie. no longer up-to-date). *)
  268. property Dirty: boolean read FDirty write FDirty;
  269. (* Memory Size of the raw data in bytes. *)
  270. property DataSize: Integer read FDataSize;
  271. (* Access to data as a byte array (n = y*Size+x).
  272. If TGLHeightData is not of type hdtByte, this value is nil. *)
  273. property ByteData: PByteArray read FByteData;
  274. (* Access to data as a byte raster (y, x).
  275. If TGLHeightData is not of type hdtByte, this value is nil. *)
  276. property ByteRaster: PByteRaster read FByteRaster;
  277. (* Access to data as a SmallInt array (n = y*Size+x).
  278. If TGLHeightData is not of type hdtSmallInt, this value is nil. *)
  279. property SmallIntData: PSmallIntArray read FSmallIntData;
  280. (* Access to data as a SmallInt raster (y, x).
  281. If TGLHeightData is not of type hdtSmallInt, this value is nil. *)
  282. property SmallIntRaster: PSmallIntRaster read FSmallIntRaster;
  283. (* Access to data as a Single array (n = y*Size+x).
  284. If TGLHeightData is not of type hdtSingle, this value is nil. *)
  285. property SingleData: PSingleArray read FSingleData;
  286. (* Access to data as a Single raster (y, x).
  287. If TGLHeightData is not of type hdtSingle, this value is nil. *)
  288. property SingleRaster: PSingleRaster read FSingleRaster;
  289. (*
  290. Name of material for the tile (if terrain uses multiple materials).
  291. property MaterialName : String read FMaterialName write FMaterialName;
  292. (WARNING: Unsafe when deleting textures! If possible, rather use LibMaterial.)
  293. *)
  294. property MaterialName: String read FMaterialName write SetMaterialName;
  295. (*
  296. property LibMaterial : Links directly to the tile's TGLLibMaterial.
  297. Unlike 'MaterialName', this property also registers the tile as
  298. a user of the texture.
  299. This prevents TGLLibMaterials.DeleteUnusedTextures from deleting the
  300. used texture by mistake and causing Access Violations.
  301. Use this instead of the old MaterialName property, to prevent AV's.
  302. *)
  303. property LibMaterial: TGLLibMaterial read FLibMaterial write SetLibMaterial;
  304. (* Texture coordinates generation mode.
  305. Default is tcmWorld coordinates. *)
  306. property TextureCoordinatesMode: THDTextureCoordinatesMode
  307. read FTextureCoordinatesMode write FTextureCoordinatesMode;
  308. property TextureCoordinatesOffset: TTexPoint read FTCOffset write FTCOffset;
  309. property TextureCoordinatesScale: TTexPoint read FTCScale write FTCScale;
  310. (* Height of point x, y as a Byte. *)
  311. function ByteHeight(x, y: Integer): Byte;
  312. (* Height of point x, y as a SmallInt. *)
  313. function SmallIntHeight(x, y: Integer): SmallInt;
  314. (* Height of point x, y as a Single. *)
  315. function SingleHeight(x, y: Integer): Single;
  316. (* Interopolated height of point x, y as a Single. *)
  317. function InterpolatedHeight(x, y: Single): Single;
  318. (* Minimum height in the tile.
  319. DataSources may assign a value to prevent automatic computation
  320. if they have a faster/already computed value. *)
  321. property HeightMin: Single read GetHeightMin write FHeightMin;
  322. (* Maximum height in the tile.
  323. DataSources may assign a value to prevent automatic computation
  324. if they have a faster/already computed value. *)
  325. property HeightMax: Single read GetHeightMax write FHeightMax;
  326. (* Returns the height as a single, whatever the DataType (slow). *)
  327. function Height(x, y: Integer): Single;
  328. (* Calculates and returns the normal for vertex point x, y.
  329. Sub classes may provide normal cacheing, the default implementation
  330. being rather blunt. *)
  331. function Normal(x, y: Integer; const scale: TAffineVector): TAffineVector;
  332. (* Calculates and returns the normal for cell x, y.(between vertexes) *)
  333. function NormalAtNode(x, y: Integer; const scale: TAffineVector): TAffineVector;
  334. (* Returns True if the data tile overlaps the area. *)
  335. function OverlapsArea(const Area: TRect): boolean;
  336. (* Reserved for renderer use. *)
  337. property ObjectTag: TObject read FObjectTag write FObjectTag;
  338. (* Reserved for renderer use. *)
  339. property Tag: Integer read FTag write FTag;
  340. (* Reserved for renderer use. *)
  341. property Tag2: Integer read FTag2 write FTag2;
  342. (* Used by perlin HDS. *)
  343. property Thread: TGLHeightDataThread read FThread write FThread;
  344. end;
  345. (* A thread specialized for processing TGLHeightData in background.
  346. Requirements:
  347. must have FreeOnTerminate set to true,
  348. must check and honour Terminated swiftly *)
  349. TGLHeightDataThread = class(TThread)
  350. protected
  351. FHeightData: TGLHeightData;
  352. public
  353. destructor Destroy; override;
  354. (* The Height Data the thread is to prepare. *)
  355. property HeightData: TGLHeightData read FHeightData write FHeightData;
  356. end;
  357. (* Bitmap-based Height Data Source.
  358. The image is automatically wrapped if requested data is out of picture Size,
  359. or if requested data is larger than the picture.
  360. The internal format is an 8 bit bitmap whose dimensions are a power of two,
  361. if the original image does not comply, it is StretchDraw'ed on a monochrome
  362. (gray) bitmap. *)
  363. TGLBitmapHDS = class(TGLHeightDataSource)
  364. private
  365. FScanLineCache: array of PByteArray;
  366. FBitmap: TBitmap;
  367. FPicture: TPicture;
  368. FInfiniteWrap: boolean;
  369. FInverted: boolean;
  370. protected
  371. procedure SetPicture(const Val: TPicture);
  372. procedure OnPictureChanged(sender: TObject);
  373. procedure SetInfiniteWrap(Val: boolean);
  374. procedure SetInverted(Val: boolean);
  375. procedure CreateMonochromeBitmap(size: Integer);
  376. procedure FreeMonochromeBitmap;
  377. function GetScanLine(y: Integer): PByteArray;
  378. public
  379. constructor Create(AOwner: TComponent); override;
  380. destructor Destroy; override;
  381. procedure StartPreparingData(HeightData: TGLHeightData); override;
  382. procedure MarkDirty(const Area: TRect); override;
  383. function Width: Integer; override;
  384. function Height: Integer; override;
  385. published
  386. (* The picture serving as Height field data reference.
  387. The picture is (if not already) internally converted to a 8 bit
  388. bitmap (grayscale). For better performance and to save memory,
  389. feed it this format! *)
  390. property Picture: TPicture read FPicture write SetPicture;
  391. (* If true the height field is wrapped indefinetely. *)
  392. property InfiniteWrap: boolean read FInfiniteWrap write SetInfiniteWrap
  393. default True;
  394. (* If true, the rendered terrain is a mirror image of the input data. *)
  395. property Inverted: boolean read FInverted write SetInverted default True;
  396. property MaxPoolSize;
  397. end;
  398. TStartPreparingDataEvent = procedure(HeightData: TGLHeightData) of object;
  399. TMarkDirtyEvent = procedure(const Area: TRect) of object;
  400. // TTexturedHeightDataSource = class (TGLTexturedHeightDataSource)
  401. (* An Height Data Source for custom use.
  402. Provides event handlers for the various requests to be implemented
  403. application-side (for application-specific needs). *)
  404. TGLCustomHDS = class(TGLHeightDataSource)
  405. private
  406. FOnStartPreparingData: TStartPreparingDataEvent;
  407. FOnMarkDirty: TMarkDirtyEvent;
  408. public
  409. constructor Create(AOwner: TComponent); override;
  410. destructor Destroy; override;
  411. procedure StartPreparingData(HeightData: TGLHeightData); override;
  412. procedure MarkDirty(const Area: TRect); override;
  413. published
  414. property MaxPoolSize;
  415. property OnStartPreparingData: TStartPreparingDataEvent
  416. read FOnStartPreparingData write FOnStartPreparingData;
  417. property OnMarkDirtyEvent: TMarkDirtyEvent read FOnMarkDirty
  418. write FOnMarkDirty;
  419. end;
  420. (* TerrainBase-based Height Data Source.
  421. This component takes its data from the TerrainBase Gobal Terrain Model.
  422. Though it can be used directly, the resolution of the TerrainBase dataset
  423. isn't high enough for accurate short-range representation and the data
  424. should rather be used as basis for further (fractal) refinement.
  425. TerrainBase is freely available from the National Geophysical Data Center
  426. and World Data Center web site (http://ngdc.noaa.com).
  427. (this component expects to find "tbase.bin" in the current directory). *)
  428. TGLTerrainBaseHDS = class(TGLHeightDataSource)
  429. public
  430. constructor Create(AOwner: TComponent); override;
  431. destructor Destroy; override;
  432. procedure StartPreparingData(HeightData: TGLHeightData); override;
  433. published
  434. property MaxPoolSize;
  435. end;
  436. TGLHeightDataSourceFilter = Class;
  437. TSourceDataFetchedEvent = procedure(sender: TGLHeightDataSourceFilter;
  438. HeightData: TGLHeightData) of object;
  439. (* Height Data Source Filter.
  440. This component sits between the TGLTerrainRenderer, and a real TGLHeightDataSource.
  441. i.e. TGLTerrainRenderer links to this. This links to the real TGLHeightDataSource.
  442. Use the 'HeightDataSource' property, to link to a source HDS.
  443. The 'OnSourceDataFetched' event then gives you the opportunity to make any changes,
  444. or link in a texture to the TGLHeightData object, BEFORE it is cached.
  445. It bypasses the cache of the source HDS, by calling the source's StartPreparingData procedure directly.
  446. The TGLHeightData objects are then cached by THIS component, AFTER you have made your changes.
  447. This eliminates the need to copy and release the TGLHeightData object from the Source HDS's cache,
  448. before linking your texture. See the new version of TGLBumpmapHDS for an example. (LIN)
  449. To create your own HDSFilters, Derive from this component, and override the PreparingData procedure. *)
  450. TGLHeightDataSourceFilter = Class(TGLHeightDataSource)
  451. private
  452. FHDS: TGLHeightDataSource;
  453. FOnSourceDataFetched: TSourceDataFetchedEvent;
  454. FActive: boolean;
  455. protected
  456. (* PreparingData:
  457. Override this function in your filter subclasses, to make any
  458. updates/changes to HeightData, before it goes into the cache.
  459. Make sure any code in this function is thread-safe, in case TAsyncHDS was used. *)
  460. procedure PreparingData(HeightData: TGLHeightData); virtual; abstract;
  461. procedure SetHDS(Val: TGLHeightDataSource);
  462. public
  463. constructor Create(AOwner: TComponent); override;
  464. destructor Destroy; override;
  465. procedure Release(aHeightData: TGLHeightData); override;
  466. procedure StartPreparingData(HeightData: TGLHeightData); override;
  467. procedure Notification(AComponent: TComponent;
  468. Operation: TOperation); override;
  469. function Width: Integer; override;
  470. function Height: Integer; override;
  471. property OnSourceDataFetched: TSourceDataFetchedEvent
  472. read FOnSourceDataFetched write FOnSourceDataFetched;
  473. published
  474. property MaxPoolSize;
  475. property HeightDataSource: TGLHeightDataSource read FHDS write SetHDS;
  476. property Active: boolean read FActive write FActive;
  477. // If Active=False, height data passes through unchanged
  478. end;
  479. // ------------------------------------------------------------------
  480. implementation
  481. // ------------------------------------------------------------------
  482. // ------------------
  483. // ------------------ TGLHeightDataSourceThread ------------------
  484. // ------------------
  485. type
  486. TGLHeightDataSourceThread = class(TThread)
  487. FOwner: TGLHeightDataSource;
  488. FIdleLoops: Integer;
  489. procedure Execute; override;
  490. function WaitForTile(HD: TGLHeightData; seconds: Integer): boolean;
  491. procedure HDSIdle;
  492. end;
  493. procedure TGLHeightDataSourceThread.Execute;
  494. var
  495. i: Integer;
  496. lst: TList;
  497. HD: TGLHeightData;
  498. max: Integer;
  499. TdCtr: Integer;
  500. begin
  501. while not Terminated do
  502. begin
  503. max := FOwner.MaxThreads;
  504. lst := FOwner.FData.LockList;
  505. // --count active threads--
  506. i := 0;
  507. TdCtr := 0;
  508. while (i < lst.Count) and (TdCtr < max) do
  509. begin
  510. if TGLHeightData(lst.Items[i]).FThread <> nil then
  511. Inc(TdCtr);
  512. Inc(i);
  513. end;
  514. // ------------------------
  515. // --Find the queued tiles, and Start preparing them--
  516. i := 0;
  517. While ((i < lst.Count) and (TdCtr < max)) do
  518. begin
  519. HD := TGLHeightData(lst.Items[i]);
  520. if HD.DataState = hdsQueued then
  521. begin
  522. FOwner.StartPreparingData(HD); // prepare
  523. Inc(TdCtr);
  524. end;
  525. Inc(i);
  526. end;
  527. // ---------------------------------------------------
  528. FOwner.FData.UnlockList;
  529. if (TdCtr = 0) then
  530. synchronize(HDSIdle);
  531. if (TdCtr = 0) then
  532. Sleep(10)
  533. else
  534. Sleep(0); // sleep longer if no Queued tiles were found
  535. end;
  536. end;
  537. // When Threading, wait a specified time, for the tile to finish preparing
  538. function TGLHeightDataSourceThread.WaitForTile(HD: TGLHeightData;
  539. seconds: Integer): boolean;
  540. var
  541. // i:integer;
  542. eTime: TDateTime;
  543. begin
  544. eTime := now + (1000 * seconds);
  545. while (HD.FThread <> nil) and (now < eTime) do
  546. begin
  547. sleep(0);
  548. end;
  549. Result := (HD.FThread = nil); // true if the thread has finished
  550. end;
  551. // When using threads, HDSIdle is called in the main thread,
  552. // whenever all HDS threads have finished, AND no queued tiles were found.
  553. // (GLS.AsyncHDS uses this for the OnIdle event.)
  554. procedure TGLHeightDataSourceThread.HDSIdle;
  555. begin
  556. self.FOwner.ThreadIsIdle;
  557. end;
  558. // ------------------
  559. // ------------------ TGLHeightDataSource ------------------
  560. // ------------------
  561. constructor TGLHeightDataSource.Create(AOwner: TComponent);
  562. var
  563. i: Integer;
  564. begin
  565. inherited Create(AOwner);
  566. FHeightDataClass := TGLHeightData;
  567. FData := TThreadList.Create;
  568. for i := 0 to High(FDataHash) do
  569. FDataHash[i] := TList.Create;
  570. // FReleaseLatency:=15/(3600*24);
  571. FThread := TGLHeightDataSourceThread.Create(True);
  572. FThread.FreeOnTerminate := False;
  573. TGLHeightDataSourceThread(FThread).FOwner := self;
  574. if self.MaxThreads > 0 then
  575. FThread.Start;
  576. end;
  577. destructor TGLHeightDataSource.Destroy;
  578. var
  579. i: Integer;
  580. begin
  581. inherited Destroy;
  582. if Assigned(FThread) then
  583. begin
  584. FThread.Terminate;
  585. FThread.Start;
  586. FThread.WaitFor;
  587. FThread.Free;
  588. end;
  589. Clear;
  590. FData.Free;
  591. for i := 0 to High(FDataHash) do
  592. FDataHash[i].Free;
  593. end;
  594. procedure TGLHeightDataSource.Clear;
  595. var
  596. i: Integer;
  597. begin
  598. with FData.LockList do
  599. begin
  600. try
  601. for i := 0 to Count - 1 do
  602. if TGLHeightData(Items[i]).UseCounter > 0 then
  603. if not(csDestroying in ComponentState) then
  604. raise Exception.Create('ERR: HeightData still in use');
  605. for i := 0 to Count - 1 do
  606. begin
  607. TGLHeightData(Items[i]).FOwner := nil;
  608. TGLHeightData(Items[i]).Free;
  609. end;
  610. for i := 0 to High(FDataHash) do
  611. FDataHash[i].Clear;
  612. Clear;
  613. finally
  614. FData.UnlockList;
  615. end;
  616. end;
  617. end;
  618. function TGLHeightDataSource.HashKey(XLeft, YTop: Integer): Integer;
  619. begin
  620. Result := (XLeft + (XLeft shr 8) + (YTop shl 1) + (YTop shr 7)) and
  621. High(FDataHash);
  622. end;
  623. function TGLHeightDataSource.FindMatchInList(XLeft, YTop, size: Integer;
  624. DataType: TGLHeightDataType): TGLHeightData;
  625. var
  626. i: Integer;
  627. HD: TGLHeightData;
  628. begin
  629. Result := nil;
  630. FData.LockList;
  631. try
  632. with FDataHash[HashKey(XLeft, YTop)] do
  633. for i := 0 to Count - 1 do
  634. begin
  635. HD := TGLHeightData(Items[i]);
  636. // if (not hd.Dirty) and (hd.XLeft=xLeft) and (hd.YTop=YTop) and (hd.Size=Size) and (hd.DataType=DataType) then begin
  637. if (HD.XLeft = XLeft) and (HD.YTop = YTop) and (HD.size = size) and
  638. (HD.DataType = DataType) and (HD.DontUse = false) then
  639. begin
  640. Result := HD;
  641. Break;
  642. end;
  643. end;
  644. finally
  645. FData.UnlockList;
  646. end;
  647. end;
  648. function TGLHeightDataSource.GetData(XLeft, YTop, size: Integer;
  649. DataType: TGLHeightDataType): TGLHeightData;
  650. begin
  651. Result := FindMatchInList(XLeft, YTop, size, DataType);
  652. if not Assigned(Result) then
  653. Result := PreLoad(XLeft, YTop, size, DataType)
  654. else
  655. with FData.LockList do
  656. begin
  657. try
  658. Move(IndexOf(Result), 0); // Moves item to the beginning of the list.
  659. finally
  660. FData.UnlockList;
  661. end;
  662. end;
  663. // got one... can be used ?
  664. // while not (Result.DataState in [hdsReady, hdsNone]) do Sleep(0);
  665. end;
  666. function TGLHeightDataSource.PreLoad(XLeft, YTop, size: Integer;
  667. DataType: TGLHeightDataType): TGLHeightData;
  668. begin
  669. Result := HeightDataClass.Create(self, XLeft, YTop, size, DataType);
  670. with FData.LockList do
  671. try
  672. Add(Result);
  673. BeforePreparingData(Result);
  674. FDataHash[HashKey(XLeft, YTop)].Add(Result);
  675. finally
  676. FData.UnlockList;
  677. end;
  678. // -- When NOT using Threads, fully prepare the tile immediately--
  679. if MaxThreads = 0 then
  680. begin
  681. StartPreparingData(Result);
  682. AfterPreparingData(Result);
  683. end;
  684. // ---------------------------------------------------------------
  685. end;
  686. // When Multi-threading, this queues a replacement for a dirty tile
  687. // The Terrain renderer will continue to use the dirty tile, until the replacement is complete
  688. procedure TGLHeightDataSource.PreloadReplacement(aHeightData: TGLHeightData);
  689. var
  690. HD: TGLHeightData;
  691. NewHD: TGLHeightData;
  692. begin
  693. Assert(MaxThreads > 0);
  694. HD := aHeightData;
  695. NewHD := HeightDataClass.Create(self, HD.XLeft, HD.YTop, HD.size,
  696. HD.DataType);
  697. with FData.LockList do
  698. try
  699. Add(NewHD);
  700. NewHD.OldVersion := HD; // link
  701. HD.NewVersion := NewHD; // link
  702. NewHD.DontUse := True;
  703. BeforePreparingData(NewHD);
  704. FDataHash[HashKey(HD.XLeft, HD.YTop)].Add(NewHD);
  705. finally
  706. FData.UnlockList;
  707. end;
  708. end;
  709. procedure TGLHeightDataSource.Release(aHeightData: TGLHeightData);
  710. begin
  711. // nothing, yet
  712. end;
  713. procedure TGLHeightDataSource.MarkDirty(const Area: TRect);
  714. var
  715. i: Integer;
  716. HD: TGLHeightData;
  717. begin
  718. with FData.LockList do
  719. begin
  720. try
  721. for i := Count - 1 downto 0 do
  722. begin
  723. HD := TGLHeightData(Items[i]);
  724. if HD.OverlapsArea(Area) then
  725. HD.MarkDirty;
  726. end;
  727. finally
  728. FData.UnlockList;
  729. end;
  730. end;
  731. end;
  732. procedure TGLHeightDataSource.MarkDirty(XLeft, YTop, xRight, yBottom: Integer);
  733. var
  734. r: TRect;
  735. begin
  736. r.Left := XLeft;
  737. r.Top := YTop;
  738. r.Right := xRight;
  739. r.Bottom := yBottom;
  740. MarkDirty(r);
  741. end;
  742. procedure TGLHeightDataSource.MarkDirty;
  743. const
  744. m = MaxInt - 1;
  745. begin
  746. MarkDirty(-m, -m, m, m);
  747. end;
  748. procedure TGLHeightDataSource.CleanUp;
  749. var
  750. packList: boolean;
  751. i, k: Integer;
  752. usedMemory: Integer;
  753. HD: TGLHeightData;
  754. ReleaseThis: boolean;
  755. begin
  756. with FData.LockList do
  757. begin
  758. try
  759. usedMemory := 0;
  760. packList := false;
  761. // Cleanup dirty tiles and compute used memory
  762. for i := Count - 1 downto 0 do
  763. begin
  764. HD := TGLHeightData(Items[i]);
  765. if HD <> nil then
  766. with HD do
  767. begin
  768. // --Release criteria for dirty tiles--
  769. ReleaseThis := false;
  770. if HD.Dirty then
  771. begin // Only release dirty tiles
  772. if (MaxThreads = 0) then
  773. ReleaseThis := True
  774. // when not threading, delete ALL dirty tiles
  775. else if (HD.DataState <> hdsPreparing) then
  776. begin // Dont release Preparing tiles
  777. if (HD.UseCounter = 0) then
  778. ReleaseThis := True; // This tile is unused
  779. if (HD.NewVersion = nil) then
  780. ReleaseThis := True
  781. // This tile has no queued replacement to wait for
  782. else if (HD.DontUse) then
  783. ReleaseThis := True; // ??This tile has already been replaced.
  784. end;
  785. end;
  786. // ------------------------------------
  787. // if Dirty then ReleaseThis:=true;
  788. if ReleaseThis then
  789. begin
  790. FDataHash[HashKey(HD.XLeft, HD.YTop)].Remove(HD);
  791. Items[i] := nil;
  792. FOwner := nil;
  793. Free;
  794. packList := True;
  795. end
  796. else
  797. usedMemory := usedMemory + HD.DataSize;
  798. end;
  799. end;
  800. // If MaxPoolSize exceeded, release all that may be, and pack the list
  801. k := 0;
  802. if usedMemory > MaxPoolSize then
  803. begin
  804. for i := 0 to Count - 1 do
  805. begin
  806. HD := TGLHeightData(Items[i]);
  807. if HD <> nil then
  808. with HD do
  809. begin
  810. if (DataState <> hdsPreparing) and (UseCounter = 0) and
  811. (OldVersion = nil)
  812. // if (DataState=hdsReady)and(UseCounter=0)and(OldVersion=nil)
  813. then
  814. begin
  815. FDataHash[HashKey(HD.XLeft, HD.YTop)].Remove(HD);
  816. Items[i] := nil;
  817. FOwner := nil;
  818. Free;
  819. // packList:=True;
  820. end
  821. else
  822. begin
  823. Items[k] := HD;
  824. Inc(k);
  825. end;
  826. end;
  827. end;
  828. Count := k;
  829. end
  830. else if packList then
  831. begin
  832. for i := 0 to Count - 1 do
  833. if Items[i] <> nil then
  834. begin
  835. Items[k] := Items[i];
  836. Inc(k);
  837. end;
  838. Count := k;
  839. end;
  840. finally
  841. FData.UnlockList;
  842. end;
  843. end;
  844. end;
  845. procedure TGLHeightDataSource.SetMaxThreads(const Val: Integer);
  846. begin
  847. if (Val <= 0) then
  848. FMaxThreads := 0
  849. else
  850. begin
  851. // If we didn't do threading, but will now
  852. // resume our thread
  853. if (FMaxThreads <= 0) then
  854. FThread.Start;
  855. FMaxThreads := Val;
  856. end;
  857. end;
  858. // Called BEFORE StartPreparingData, but always from the MAIN thread.
  859. // Override this in subclasses, to prepare for Threading.
  860. procedure TGLHeightDataSource.BeforePreparingData(HeightData: TGLHeightData);
  861. begin
  862. //
  863. end;
  864. // When Threads are used, this runs from the sub-thread, so this MUST be thread-safe.
  865. // Any Non-thread-safe code should be placed in "BeforePreparingData"
  866. procedure TGLHeightDataSource.StartPreparingData(HeightData: TGLHeightData);
  867. begin
  868. // Only the tile Owner may set the preparing tile to ready
  869. if (HeightData.Owner = self) and (HeightData.DataState = hdsPreparing) then
  870. HeightData.FDataState := hdsReady;
  871. end;
  872. // Called AFTER StartPreparingData, but always from the MAIN thread.
  873. // Override this in subclasses, if needed.
  874. procedure TGLHeightDataSource.AfterPreparingData(HeightData: TGLHeightData);
  875. begin
  876. //
  877. end;
  878. procedure TGLHeightDataSource.ThreadIsIdle;
  879. begin
  880. // TGLAsyncHDS overrides this
  881. end;
  882. // Calculates texture World texture coordinates for the current tile.
  883. // Use Stretch for OpenGL1.1, to hide the seams when using linear filtering.
  884. procedure TGLHeightDataSource.TextureCoordinates(HeightData: TGLHeightData;
  885. Stretch: boolean = false);
  886. var
  887. w, h, size: Integer;
  888. scaleS, scaleT: Single;
  889. offsetS, offsetT: Single;
  890. HD: TGLHeightData;
  891. halfpixel: Single;
  892. begin
  893. HD := HeightData;
  894. w := self.Width;
  895. h := self.Height;
  896. size := HD.FSize;
  897. // if GL_VERSION_1_2 then begin //OpenGL1.2 supports texture clamping, so seams dont show.
  898. if Stretch = false then
  899. begin // These are the real Texture coordinates
  900. scaleS := w / (size - 1);
  901. scaleT := h / (size - 1);
  902. offsetS := -((HD.XLeft / w) * scaleS);
  903. offsetT := -(h - (HD.YTop + size - 1)) / (size - 1);
  904. end
  905. else
  906. begin // --Texture coordinates: Stretched by 1 pixel, to hide seams on OpenGL-1.1(no Clamping)--
  907. scaleS := w / size;
  908. scaleT := h / size;
  909. halfpixel := 1 / (size shr 1);
  910. offsetS := -((HD.XLeft / w) * scaleS) + halfpixel;
  911. offsetT := -(h - (HD.YTop + size)) / size - halfpixel;
  912. end;
  913. HD.FTCScale.S := scaleS;
  914. HD.FTCScale.T := scaleT;
  915. HD.FTCOffset.S := offsetS;
  916. HD.FTCOffset.T := offsetT;
  917. end;
  918. function TGLHeightDataSource.InterpolatedHeight(x, y: Single;
  919. TileSize: Integer): Single;
  920. var
  921. i: Integer;
  922. HD, foundHd: TGLHeightData;
  923. begin
  924. with FData.LockList do
  925. begin
  926. try
  927. // first, lookup data list to find if aHeightData contains our point
  928. foundHd := nil;
  929. for i := 0 to Count - 1 do
  930. begin
  931. HD := TGLHeightData(Items[i]);
  932. if (HD.XLeft <= x) and (HD.YTop <= y) and (HD.XLeft + HD.size - 1 > x)
  933. and (HD.YTop + HD.size - 1 > y) then
  934. begin
  935. foundHd := HD;
  936. Break;
  937. end;
  938. end;
  939. finally
  940. FData.UnlockList;
  941. end;
  942. end;
  943. if (foundHd = nil) or foundHd.Dirty then
  944. begin
  945. // not found, request one... slowest mode (should be avoided)
  946. if TileSize > 1 then
  947. foundHd := GetData(Round(x / (TileSize - 1) - 0.5) * (TileSize - 1),
  948. Round(y / (TileSize - 1) - 0.5) * (TileSize - 1), TileSize, hdtDefault)
  949. else
  950. begin
  951. Result := DefaultHeight;
  952. Exit;
  953. end;
  954. end
  955. else
  956. begin
  957. // request it using "standard" way (takes care of threads)
  958. foundHd := GetData(foundHd.XLeft, foundHd.YTop, foundHd.size,
  959. foundHd.DataType);
  960. end;
  961. if foundHd.DataState = hdsNone then
  962. Result := DefaultHeight
  963. else
  964. Result := foundHd.InterpolatedHeight(x - foundHd.XLeft, y - foundHd.YTop);
  965. end;
  966. // ------------------
  967. // ------------------ TGLHeightData ------------------
  968. // ------------------
  969. constructor TGLHeightData.Create(AOwner: TGLHeightDataSource;
  970. aXLeft, aYTop, aSize: Integer; aDataType: TGLHeightDataType);
  971. begin
  972. inherited Create(AOwner);
  973. SetLength(FUsers, 0);
  974. FOwner := AOwner;
  975. FXLeft := aXLeft;
  976. FYTop := aYTop;
  977. FSize := aSize;
  978. FTextureCoordinatesMode := tcmWorld;
  979. FTCScale := XYTexPoint;
  980. FDataType := aDataType;
  981. FDataState := hdsQueued;
  982. FHeightMin := 1E30;
  983. FHeightMax := 1E30;
  984. OldVersion := nil;
  985. NewVersion := nil;
  986. DontUse := False;
  987. end;
  988. destructor TGLHeightData.Destroy;
  989. begin
  990. Assert(Length(FUsers) = 0,
  991. 'You should *not* free a TGLHeightData, use "Release" instead');
  992. Assert(not Assigned(FOwner),
  993. 'You should *not* free a TGLHeightData, use "Release" instead');
  994. if Assigned(FThread) then
  995. begin
  996. FThread.Terminate;
  997. if FThread.Suspended then
  998. FThread.Start;
  999. FThread.WaitFor;
  1000. end;
  1001. if Assigned(FOnDestroy) then
  1002. FOnDestroy(self);
  1003. case DataType of
  1004. hdtByte:
  1005. begin
  1006. FreeMem(FByteData);
  1007. FreeMem(FByteRaster);
  1008. end;
  1009. hdtSmallInt:
  1010. begin
  1011. FreeMem(FSmallIntData);
  1012. FreeMem(FSmallIntRaster);
  1013. end;
  1014. hdtSingle:
  1015. begin
  1016. FreeMem(FSingleData);
  1017. FreeMem(FSingleRaster);
  1018. end;
  1019. hdtDefault:
  1020. ; // nothing
  1021. else
  1022. Assert(False);
  1023. end;
  1024. // ----------------------
  1025. self.LibMaterial := nil; // release a used material
  1026. // --Break any link with a new/old version of this tile--
  1027. if Assigned(self.OldVersion) then
  1028. begin
  1029. self.OldVersion.NewVersion := nil;
  1030. self.OldVersion := nil;
  1031. end;
  1032. if Assigned(self.NewVersion) then
  1033. begin
  1034. self.NewVersion.OldVersion := nil;
  1035. self.NewVersion := nil;
  1036. end;
  1037. // ------------------------------------------------------
  1038. // ----------------------
  1039. inherited Destroy;
  1040. end;
  1041. procedure TGLHeightData.RegisterUse;
  1042. begin
  1043. Inc(FUseCounter);
  1044. end;
  1045. // Release
  1046. //
  1047. procedure TGLHeightData.Release;
  1048. begin
  1049. if FUseCounter > 0 then
  1050. Dec(FUseCounter);
  1051. if FUseCounter = 0 then
  1052. begin
  1053. Owner.Release(self); // ???
  1054. end;
  1055. end;
  1056. // Release Dirty tiles, unless threading, and the tile is being used.
  1057. // In that case, start building a replacement tile instead.
  1058. procedure TGLHeightData.MarkDirty;
  1059. begin
  1060. with Owner.Data.LockList do
  1061. try
  1062. if (not Dirty) and (DataState <> hdsQueued) then
  1063. begin // dont mark queued tiles as dirty
  1064. FDirty := True;
  1065. if (Owner.MaxThreads > 0) and (FUseCounter > 0) then
  1066. Owner.PreloadReplacement(self)
  1067. else
  1068. begin
  1069. FUseCounter := 0;
  1070. Owner.Release(self);
  1071. end;
  1072. end;
  1073. finally
  1074. Owner.Data.UnlockList;
  1075. end;
  1076. end;
  1077. procedure TGLHeightData.Allocate(const Val: TGLHeightDataType);
  1078. begin
  1079. Assert(FDataSize = 0);
  1080. case Val of
  1081. hdtByte:
  1082. begin
  1083. FDataSize := size * size * SizeOf(Byte);
  1084. GetMem(FByteData, FDataSize);
  1085. BuildByteRaster;
  1086. end;
  1087. hdtSmallInt:
  1088. begin
  1089. FDataSize := size * size * SizeOf(SmallInt);
  1090. GetMem(FSmallIntData, FDataSize);
  1091. BuildSmallIntRaster;
  1092. end;
  1093. hdtSingle:
  1094. begin
  1095. FDataSize := size * size * SizeOf(Single);
  1096. GetMem(FSingleData, FDataSize);
  1097. BuildSingleRaster;
  1098. end;
  1099. else
  1100. Assert(false);
  1101. end;
  1102. FDataType := Val;
  1103. end;
  1104. // WARNING: SetMaterialName does NOT register the tile as a user of this texture.
  1105. // So, TGLLibMaterials.DeleteUnusedMaterials may see this material as unused, and delete it.
  1106. // This may lead to AV's the next time this tile is rendered.
  1107. // To be safe, rather assign the new TGLHeightData.LibMaterial property
  1108. procedure TGLHeightData.SetMaterialName(const MaterialName: string);
  1109. begin
  1110. SetLibMaterial(nil);
  1111. FMaterialName := MaterialName;
  1112. end;
  1113. procedure TGLHeightData.SetLibMaterial(LibMaterial: TGLLibMaterial);
  1114. begin
  1115. if Assigned(FLibMaterial) then
  1116. FLibMaterial.UnregisterUser(self); // detach from old texture
  1117. FLibMaterial := LibMaterial; // Attach new Material
  1118. if Assigned(LibMaterial) then
  1119. begin
  1120. LibMaterial.RegisterUser(self); // Mark new Material as 'used'
  1121. FMaterialName := LibMaterial.Name; // sync up MaterialName property
  1122. end
  1123. else
  1124. FMaterialName := '';
  1125. end;
  1126. procedure TGLHeightData.SetDataType(const Val: TGLHeightDataType);
  1127. begin
  1128. if (Val <> FDataType) and (Val <> hdtDefault) then
  1129. begin
  1130. if DataState <> hdsNone then
  1131. begin
  1132. case FDataType of
  1133. hdtByte:
  1134. case Val of
  1135. hdtSmallInt:
  1136. ConvertByteToSmallInt;
  1137. hdtSingle:
  1138. ConvertByteToSingle;
  1139. else
  1140. Assert(False);
  1141. end;
  1142. hdtSmallInt:
  1143. case Val of
  1144. hdtByte:
  1145. ConvertSmallIntToByte;
  1146. hdtSingle:
  1147. ConvertSmallIntToSingle;
  1148. else
  1149. Assert(False);
  1150. end;
  1151. hdtSingle:
  1152. case Val of
  1153. hdtByte:
  1154. ConvertSingleToByte;
  1155. hdtSmallInt:
  1156. ConvertSingleToSmallInt;
  1157. else
  1158. Assert(False);
  1159. end;
  1160. hdtDefault:
  1161. ; // nothing, assume StartPreparingData knows what it's doing
  1162. else
  1163. Assert(False);
  1164. end;
  1165. end;
  1166. FDataType := Val;
  1167. end;
  1168. end;
  1169. procedure TGLHeightData.BuildByteRaster;
  1170. var
  1171. i: Integer;
  1172. begin
  1173. GetMem(FByteRaster, size * SizeOf(PByteArray));
  1174. for i := 0 to size - 1 do
  1175. FByteRaster^[i] := @FByteData[i * size]
  1176. end;
  1177. procedure TGLHeightData.BuildSmallIntRaster;
  1178. var
  1179. i: Integer;
  1180. begin
  1181. GetMem(FSmallIntRaster, size * SizeOf(PSmallIntArray));
  1182. for i := 0 to size - 1 do
  1183. FSmallIntRaster^[i] := @FSmallIntData[i * size]
  1184. end;
  1185. procedure TGLHeightData.BuildSingleRaster;
  1186. var
  1187. i: Integer;
  1188. begin
  1189. GetMem(FSingleRaster, size * SizeOf(PSingleArray));
  1190. for i := 0 to size - 1 do
  1191. FSingleRaster^[i] := @FSingleData[i * size]
  1192. end;
  1193. procedure TGLHeightData.ConvertByteToSmallInt;
  1194. var
  1195. i: Integer;
  1196. begin
  1197. FreeMem(FByteRaster);
  1198. FByteRaster := nil;
  1199. FDataSize := size * size * SizeOf(SmallInt);
  1200. GetMem(FSmallIntData, FDataSize);
  1201. for i := 0 to size * size - 1 do
  1202. FSmallIntData^[i] := (FByteData^[i] - 128) shl 7;
  1203. FreeMem(FByteData);
  1204. FByteData := nil;
  1205. BuildSmallIntRaster;
  1206. end;
  1207. procedure TGLHeightData.ConvertByteToSingle;
  1208. var
  1209. i: Integer;
  1210. begin
  1211. FreeMem(FByteRaster);
  1212. FByteRaster := nil;
  1213. FDataSize := size * size * SizeOf(Single);
  1214. GetMem(FSingleData, FDataSize);
  1215. for i := 0 to size * size - 1 do
  1216. FSingleData^[i] := (FByteData^[i] - 128) shl 7;
  1217. FreeMem(FByteData);
  1218. FByteData := nil;
  1219. BuildSingleRaster;
  1220. end;
  1221. procedure TGLHeightData.ConvertSmallIntToByte;
  1222. var
  1223. i: Integer;
  1224. begin
  1225. FreeMem(FSmallIntRaster);
  1226. FSmallIntRaster := nil;
  1227. FByteData := Pointer(FSmallIntData);
  1228. for i := 0 to size * size - 1 do
  1229. FByteData^[i] := (FSmallIntData^[i] div 128) + 128;
  1230. FDataSize := size * size * SizeOf(Byte);
  1231. ReallocMem(FByteData, FDataSize);
  1232. FSmallIntData := nil;
  1233. BuildByteRaster;
  1234. end;
  1235. procedure TGLHeightData.ConvertSmallIntToSingle;
  1236. var
  1237. i: Integer;
  1238. begin
  1239. FreeMem(FSmallIntRaster);
  1240. FSmallIntRaster := nil;
  1241. FDataSize := size * size * SizeOf(Single);
  1242. GetMem(FSingleData, FDataSize);
  1243. for i := 0 to size * size - 1 do
  1244. FSingleData^[i] := FSmallIntData^[i];
  1245. FreeMem(FSmallIntData);
  1246. FSmallIntData := nil;
  1247. BuildSingleRaster;
  1248. end;
  1249. procedure TGLHeightData.ConvertSingleToByte;
  1250. var
  1251. i: Integer;
  1252. begin
  1253. FreeMem(FSingleRaster);
  1254. FSingleRaster := nil;
  1255. FByteData := Pointer(FSingleData);
  1256. for i := 0 to size * size - 1 do
  1257. FByteData^[i] := (Round(FSingleData^[i]) div 128) + 128;
  1258. FDataSize := size * size * SizeOf(Byte);
  1259. ReallocMem(FByteData, FDataSize);
  1260. FSingleData := nil;
  1261. BuildByteRaster;
  1262. end;
  1263. procedure TGLHeightData.ConvertSingleToSmallInt;
  1264. var
  1265. i: Integer;
  1266. begin
  1267. FreeMem(FSingleRaster);
  1268. FSingleRaster := nil;
  1269. FSmallIntData := Pointer(FSingleData);
  1270. for i := 0 to size * size - 1 do
  1271. FSmallIntData^[i] := Round(FSingleData^[i]);
  1272. FDataSize := size * size * SizeOf(SmallInt);
  1273. ReallocMem(FSmallIntData, FDataSize);
  1274. FSingleData := nil;
  1275. BuildSmallIntRaster;
  1276. end;
  1277. function TGLHeightData.ByteHeight(x, y: Integer): Byte;
  1278. begin
  1279. Assert((Cardinal(x) < Cardinal(size)) and (Cardinal(y) < Cardinal(size)));
  1280. Result := ByteRaster^[y]^[x];
  1281. end;
  1282. function TGLHeightData.SmallIntHeight(x, y: Integer): SmallInt;
  1283. begin
  1284. Assert((Cardinal(x) < Cardinal(size)) and (Cardinal(y) < Cardinal(size)));
  1285. Result := SmallIntRaster^[y]^[x];
  1286. end;
  1287. function TGLHeightData.SingleHeight(x, y: Integer): Single;
  1288. begin
  1289. Assert((Cardinal(x) < Cardinal(size)) and (Cardinal(y) < Cardinal(size)));
  1290. Result := SingleRaster^[y]^[x];
  1291. end;
  1292. function TGLHeightData.InterpolatedHeight(x, y: Single): Single;
  1293. var
  1294. ix, iy, ixn, iyn: Integer;
  1295. h1, h2, h3: Single;
  1296. begin
  1297. if FDataState = hdsNone then
  1298. Result := 0
  1299. else
  1300. begin
  1301. ix := Trunc(x);
  1302. x := Frac(x);
  1303. iy := Trunc(y);
  1304. y := Frac(y);
  1305. ixn := ix + 1;
  1306. if ixn >= size then
  1307. ixn := ix;
  1308. iyn := iy + 1;
  1309. if iyn >= size then
  1310. iyn := iy;
  1311. if x > y then
  1312. begin
  1313. // top-right triangle
  1314. h1 := Height(ixn, iy);
  1315. h2 := Height(ix, iy);
  1316. h3 := Height(ixn, iyn);
  1317. Result := h1 + (h2 - h1) * (1 - x) + (h3 - h1) * y;
  1318. end
  1319. else
  1320. begin
  1321. // bottom-left triangle
  1322. h1 := Height(ix, iyn);
  1323. h2 := Height(ixn, iyn);
  1324. h3 := Height(ix, iy);
  1325. Result := h1 + (h2 - h1) * (x) + (h3 - h1) * (1 - y);
  1326. end;
  1327. end;
  1328. end;
  1329. function TGLHeightData.Height(x, y: Integer): Single;
  1330. begin
  1331. case DataType of
  1332. hdtByte:
  1333. Result := (ByteHeight(x, y) - 128) shl 7;
  1334. hdtSmallInt:
  1335. Result := SmallIntHeight(x, y);
  1336. hdtSingle:
  1337. Result := SingleHeight(x, y);
  1338. else
  1339. Result := 0;
  1340. Assert(false);
  1341. end;
  1342. end;
  1343. function TGLHeightData.GetHeightMin: Single;
  1344. var
  1345. i: Integer;
  1346. b: Byte;
  1347. sm: SmallInt;
  1348. si: Single;
  1349. begin
  1350. if FHeightMin = 1E30 then
  1351. begin
  1352. if DataState = hdsReady then
  1353. begin
  1354. case DataType of
  1355. hdtByte:
  1356. begin
  1357. b := FByteData^[0];
  1358. for i := 1 to size * size - 1 do
  1359. if FByteData^[i] < b then
  1360. b := FByteData^[i];
  1361. FHeightMin := ((Integer(b) - 128) shl 7);
  1362. end;
  1363. hdtSmallInt:
  1364. begin
  1365. sm := FSmallIntData^[0];
  1366. for i := 1 to size * size - 1 do
  1367. if FSmallIntData^[i] < sm then
  1368. sm := FSmallIntData^[i];
  1369. FHeightMin := sm;
  1370. end;
  1371. hdtSingle:
  1372. begin
  1373. si := FSingleData^[0];
  1374. for i := 1 to size * size - 1 do
  1375. if FSingleData^[i] < si then
  1376. si := FSingleData^[i];
  1377. FHeightMin := si;
  1378. end;
  1379. else
  1380. FHeightMin := 0;
  1381. end;
  1382. end
  1383. else
  1384. FHeightMin := 0;
  1385. end;
  1386. Result := FHeightMin;
  1387. end;
  1388. function TGLHeightData.GetHeightMax: Single;
  1389. var
  1390. i: Integer;
  1391. b: Byte;
  1392. sm: SmallInt;
  1393. si: Single;
  1394. begin
  1395. if FHeightMax = 1E30 then
  1396. begin
  1397. if DataState = hdsReady then
  1398. begin
  1399. case DataType of
  1400. hdtByte:
  1401. begin
  1402. b := FByteData^[0];
  1403. for i := 1 to size * size - 1 do
  1404. if FByteData^[i] > b then
  1405. b := FByteData^[i];
  1406. FHeightMax := ((Integer(b) - 128) shl 7);
  1407. end;
  1408. hdtSmallInt:
  1409. begin
  1410. sm := FSmallIntData^[0];
  1411. for i := 1 to size * size - 1 do
  1412. if FSmallIntData^[i] > sm then
  1413. sm := FSmallIntData^[i];
  1414. FHeightMax := sm;
  1415. end;
  1416. hdtSingle:
  1417. begin
  1418. si := FSingleData^[0];
  1419. for i := 1 to size * size - 1 do
  1420. if FSingleData^[i] > si then
  1421. si := FSingleData^[i];
  1422. FHeightMax := si;
  1423. end;
  1424. else
  1425. FHeightMax := 0;
  1426. end;
  1427. end
  1428. else
  1429. FHeightMax := 0;
  1430. end;
  1431. Result := FHeightMax;
  1432. end;
  1433. // Calculates the normal at a vertex
  1434. function TGLHeightData.Normal(x, y: Integer; const scale: TAffineVector)
  1435. : TAffineVector;
  1436. var
  1437. dx, dy: Single;
  1438. begin
  1439. if x > 0 then
  1440. if x < size - 1 then
  1441. dx := (Height(x + 1, y) - Height(x - 1, y))
  1442. else
  1443. dx := (Height(x, y) - Height(x - 1, y))
  1444. else
  1445. dx := (Height(x + 1, y) - Height(x, y));
  1446. if y > 0 then
  1447. if y < size - 1 then
  1448. dy := (Height(x, y + 1) - Height(x, y - 1))
  1449. else
  1450. dy := (Height(x, y) - Height(x, y - 1))
  1451. else
  1452. dy := (Height(x, y + 1) - Height(x, y));
  1453. Result.X := dx * scale.Y * scale.Z;
  1454. Result.Y := dy * scale.X * scale.Z;
  1455. Result.Z := 1 * scale.X * scale.Y;
  1456. NormalizeVector(Result);
  1457. end;
  1458. // Calculates the normal at a surface cell (Between vertexes)
  1459. function TGLHeightData.NormalAtNode(x, y: Integer; const scale: TAffineVector)
  1460. : TAffineVector;
  1461. var
  1462. dx, dy, Hxy: Single;
  1463. begin
  1464. MinInteger(MaxInteger(x, 0), size - 2); // clamp x to 0 -> Size-2
  1465. MinInteger(MaxInteger(y, 0), size - 2); // clamp x to 0 -> Size-2
  1466. Hxy := Height(x, y);
  1467. dx := Height(x + 1, y) - Hxy;
  1468. dy := Height(x, y + 1) - Hxy;
  1469. Result.X := dx * scale.Y * scale.Z; // Result.X:=dx/scale.X;
  1470. Result.Y := dy * scale.X * scale.Z; // Result.Y:=dy/scale.Y;
  1471. Result.Z := 1 * scale.X * scale.Y; // Result.Z:=1 /scale.Z;
  1472. NormalizeVector(Result);
  1473. end;
  1474. function TGLHeightData.OverlapsArea(const Area: TRect): boolean;
  1475. begin
  1476. Result := (XLeft <= Area.Right) and (YTop <= Area.Bottom) and
  1477. (XLeft + size > Area.Left) and (YTop + size > Area.Top);
  1478. end;
  1479. // ------------------
  1480. // ------------------ TGLHeightDataThread ------------------
  1481. // ------------------
  1482. destructor TGLHeightDataThread.Destroy;
  1483. begin
  1484. if Assigned(FHeightData) then
  1485. FHeightData.FThread := nil;
  1486. inherited;
  1487. end;
  1488. // ------------------
  1489. // ------------------ TGLBitmapHDS ------------------
  1490. // ------------------
  1491. constructor TGLBitmapHDS.Create(AOwner: TComponent);
  1492. begin
  1493. inherited Create(AOwner);
  1494. FPicture := TPicture.Create;
  1495. FPicture.OnChange := OnPictureChanged;
  1496. FInfiniteWrap := True;
  1497. FInverted := True;
  1498. end;
  1499. destructor TGLBitmapHDS.Destroy;
  1500. begin
  1501. inherited Destroy;
  1502. FreeMonochromeBitmap;
  1503. FPicture.Free;
  1504. end;
  1505. procedure TGLBitmapHDS.SetPicture(const Val: TPicture);
  1506. begin
  1507. FPicture.Assign(Val);
  1508. end;
  1509. procedure TGLBitmapHDS.OnPictureChanged(sender: TObject);
  1510. var
  1511. oldPoolSize, size: Integer;
  1512. begin
  1513. // cleanup pool
  1514. oldPoolSize := MaxPoolSize;
  1515. MaxPoolSize := 0;
  1516. CleanUp;
  1517. MaxPoolSize := oldPoolSize;
  1518. // prepare MonoChromeBitmap
  1519. FreeMonochromeBitmap;
  1520. size := Picture.Width;
  1521. if size > 0 then
  1522. CreateMonochromeBitmap(size);
  1523. end;
  1524. procedure TGLBitmapHDS.SetInfiniteWrap(Val: boolean);
  1525. begin
  1526. if FInfiniteWrap <> Val then
  1527. begin
  1528. FInfiniteWrap := Val;
  1529. MarkDirty;
  1530. end;
  1531. end;
  1532. procedure TGLBitmapHDS.SetInverted(Val: boolean);
  1533. begin
  1534. if FInverted = Val then
  1535. Exit;
  1536. FInverted := Val;
  1537. MarkDirty;
  1538. end;
  1539. procedure TGLBitmapHDS.MarkDirty(const Area: TRect);
  1540. begin
  1541. inherited;
  1542. FreeMonochromeBitmap;
  1543. if Picture.Width > 0 then
  1544. CreateMonochromeBitmap(Picture.Width);
  1545. end;
  1546. procedure TGLBitmapHDS.CreateMonochromeBitmap(size: Integer);
  1547. type
  1548. TPaletteEntryArray = array [0 .. 255] of TPaletteEntry;
  1549. PPaletteEntryArray = ^TPaletteEntryArray;
  1550. TLogPal = record
  1551. lpal: TLogPalette;
  1552. pe: TPaletteEntryArray;
  1553. end;
  1554. var
  1555. x: Integer;
  1556. logpal: TLogPal;
  1557. hPal: HPalette;
  1558. begin
  1559. size := RoundUpToPowerOf2(size);
  1560. FBitmap := TBitmap.Create;
  1561. FBitmap.PixelFormat := pf8bit;
  1562. FBitmap.Width := size;
  1563. FBitmap.Height := size;
  1564. for x := 0 to 255 do
  1565. with PPaletteEntryArray(@logpal.lpal.palPalEntry[0])[x] do
  1566. begin
  1567. peRed := x;
  1568. peGreen := x;
  1569. peBlue := x;
  1570. peFlags := 0;
  1571. end;
  1572. with logpal.lpal do
  1573. begin
  1574. palVersion := $300;
  1575. palNumEntries := 256;
  1576. end;
  1577. hPal := CreatePalette(logpal.lpal);
  1578. Assert(hPal <> 0);
  1579. FBitmap.Palette := hPal;
  1580. // some picture formats trigger a "change" when drawed
  1581. Picture.OnChange := nil;
  1582. try
  1583. FBitmap.Canvas.StretchDraw(Rect(0, 0, size, size), Picture.Graphic);
  1584. finally
  1585. Picture.OnChange := OnPictureChanged;
  1586. end;
  1587. SetLength(FScanLineCache, 0); // clear the cache
  1588. SetLength(FScanLineCache, size);
  1589. end;
  1590. procedure TGLBitmapHDS.FreeMonochromeBitmap;
  1591. begin
  1592. SetLength(FScanLineCache, 0);
  1593. FBitmap.Free;
  1594. FBitmap := nil;
  1595. end;
  1596. function TGLBitmapHDS.GetScanLine(y: Integer): PByteArray;
  1597. begin
  1598. Result := FScanLineCache[y];
  1599. if not Assigned(Result) then
  1600. begin
  1601. Result := FBitmap.ScanLine[y];
  1602. FScanLineCache[y] := Result;
  1603. end;
  1604. end;
  1605. procedure TGLBitmapHDS.StartPreparingData(HeightData: TGLHeightData);
  1606. var
  1607. y, x: Integer;
  1608. bmpSize, wrapMask: Integer;
  1609. bitmapLine, rasterLine: PByteArray;
  1610. oldType: TGLHeightDataType;
  1611. b: Byte;
  1612. YPos: Integer;
  1613. begin
  1614. if FBitmap = nil then
  1615. Exit;
  1616. HeightData.FDataState := hdsPreparing;
  1617. bmpSize := FBitmap.Width;
  1618. wrapMask := bmpSize - 1;
  1619. // retrieve data
  1620. with HeightData do
  1621. begin
  1622. if (not InfiniteWrap) and ((XLeft >= bmpSize) or (XLeft < 0) or
  1623. (YTop >= bmpSize) or (YTop < 0)) then
  1624. begin
  1625. HeightData.FDataState := hdsNone;
  1626. Exit;
  1627. end;
  1628. oldType := DataType;
  1629. Allocate(hdtByte);
  1630. if Inverted then
  1631. YPos := YTop
  1632. else
  1633. YPos := 1 - size - YTop;
  1634. for y := 0 to size - 1 do
  1635. begin
  1636. bitmapLine := GetScanLine((y + YPos) and wrapMask);
  1637. if Inverted then
  1638. rasterLine := ByteRaster^[y]
  1639. else
  1640. rasterLine := ByteRaster^[size - 1 - y];
  1641. // *BIG CAUTION HERE* : Don't remove the intermediate variable here!!!
  1642. // or Delphi compiler will "optimize" to 32 bits access with clamping
  1643. // Resulting in possible reads of stuff beyon bitmapLine length!!!!
  1644. for x := XLeft to XLeft + size - 1 do
  1645. begin
  1646. b := bitmapLine^[x and wrapMask];
  1647. rasterLine^[x - XLeft] := b;
  1648. end;
  1649. end;
  1650. if (oldType <> hdtByte) and (oldType <> hdtDefault) then
  1651. DataType := oldType;
  1652. end;
  1653. TextureCoordinates(HeightData);
  1654. inherited;
  1655. end;
  1656. function TGLBitmapHDS.Width: Integer;
  1657. begin
  1658. if Assigned(self.FBitmap) then
  1659. Result := self.FBitmap.Width
  1660. else
  1661. Result := 0;
  1662. end;
  1663. function TGLBitmapHDS.Height: Integer;
  1664. begin
  1665. if Assigned(self.FBitmap) then
  1666. Result := self.FBitmap.Height
  1667. else
  1668. Result := 0;
  1669. end;
  1670. // ------------------
  1671. // ------------------ TGLCustomHDS ------------------
  1672. // ------------------
  1673. constructor TGLCustomHDS.Create(AOwner: TComponent);
  1674. begin
  1675. inherited Create(AOwner);
  1676. end;
  1677. destructor TGLCustomHDS.Destroy;
  1678. begin
  1679. inherited Destroy;
  1680. end;
  1681. procedure TGLCustomHDS.MarkDirty(const Area: TRect);
  1682. begin
  1683. inherited;
  1684. if Assigned(FOnMarkDirty) then
  1685. FOnMarkDirty(Area);
  1686. end;
  1687. procedure TGLCustomHDS.StartPreparingData(HeightData: TGLHeightData);
  1688. begin
  1689. if Assigned(FOnStartPreparingData) then
  1690. FOnStartPreparingData(HeightData);
  1691. if HeightData.DataState <> hdsNone then
  1692. HeightData.DataState := hdsReady;
  1693. end;
  1694. // ------------------
  1695. // ------------------ TGLTerrainBaseHDS ------------------
  1696. // ------------------
  1697. constructor TGLTerrainBaseHDS.Create(AOwner: TComponent);
  1698. begin
  1699. inherited Create(AOwner);
  1700. end;
  1701. destructor TGLTerrainBaseHDS.Destroy;
  1702. begin
  1703. inherited Destroy;
  1704. end;
  1705. procedure TGLTerrainBaseHDS.StartPreparingData(HeightData: TGLHeightData);
  1706. const
  1707. cTBWidth: Integer = 4320;
  1708. cTBHeight: Integer = 2160;
  1709. var
  1710. y, x, offset: Integer;
  1711. rasterLine: PSmallIntArray;
  1712. oldType: TGLHeightDataType;
  1713. b: SmallInt;
  1714. fs: TStream;
  1715. begin
  1716. if not FileExists('tbase.bin') then
  1717. Exit;
  1718. fs := TFileStream.Create('tbase.bin', fmOpenRead + fmShareDenyNone);
  1719. try
  1720. // retrieve data
  1721. with HeightData do
  1722. begin
  1723. oldType := DataType;
  1724. Allocate(hdtSmallInt);
  1725. for y := YTop to YTop + size - 1 do
  1726. begin
  1727. offset := (y mod cTBHeight) * (cTBWidth * 2);
  1728. rasterLine := SmallIntRaster^[y - YTop];
  1729. for x := XLeft to XLeft + size - 1 do
  1730. begin
  1731. fs.Seek(offset + (x mod cTBWidth) * 2, soFromBeginning);
  1732. fs.Read(b, 2);
  1733. if b < 0 then
  1734. b := 0;
  1735. rasterLine^[x - XLeft] := SmallInt(b);
  1736. end;
  1737. end;
  1738. if oldType <> hdtSmallInt then
  1739. DataType := oldType;
  1740. end;
  1741. inherited;
  1742. finally
  1743. fs.Free;
  1744. end;
  1745. end;
  1746. // ------------------
  1747. // ------------------ TGLHeightDataSourceFilter ------------------
  1748. // ------------------
  1749. constructor TGLHeightDataSourceFilter.Create(AOwner: TComponent);
  1750. begin
  1751. inherited Create(AOwner);
  1752. FActive := True;
  1753. end;
  1754. destructor TGLHeightDataSourceFilter.Destroy;
  1755. begin
  1756. HeightDataSource := nil;
  1757. inherited Destroy;
  1758. end;
  1759. procedure TGLHeightDataSourceFilter.Release(aHeightData: TGLHeightData);
  1760. begin
  1761. if Assigned(HeightDataSource) then
  1762. HeightDataSource.Release(aHeightData);
  1763. end;
  1764. procedure TGLHeightDataSourceFilter.Notification(AComponent: TComponent;
  1765. Operation: TOperation);
  1766. begin
  1767. if Operation = opRemove then
  1768. begin
  1769. if AComponent = FHDS then
  1770. HeightDataSource := nil
  1771. end;
  1772. inherited;
  1773. end;
  1774. procedure TGLHeightDataSourceFilter.SetHDS(Val: TGLHeightDataSource);
  1775. begin
  1776. if Val = self then
  1777. Val := nil; // prevent self-referencing
  1778. if Val <> FHDS then
  1779. begin
  1780. if Assigned(FHDS) then
  1781. FHDS.RemoveFreeNotification(self);
  1782. FHDS := Val;
  1783. if Assigned(FHDS) then
  1784. FHDS.FreeNotification(self);
  1785. // MarkDirty;
  1786. self.Clear; // when removing the HDS, also remove all tiles from the cache
  1787. end;
  1788. end;
  1789. function TGLHeightDataSourceFilter.Width: Integer;
  1790. begin
  1791. if Assigned(FHDS) then
  1792. Result := FHDS.Width
  1793. else
  1794. Result := 0;
  1795. end;
  1796. function TGLHeightDataSourceFilter.Height: Integer;
  1797. begin
  1798. if Assigned(FHDS) then
  1799. Result := FHDS.Height
  1800. else
  1801. Result := 0;
  1802. end;
  1803. procedure TGLHeightDataSourceFilter.StartPreparingData(HeightData: TGLHeightData);
  1804. begin
  1805. // ---if there is no linked HDS then return an empty tile--
  1806. if not Assigned(FHDS) then
  1807. begin
  1808. HeightData.Owner.Data.LockList;
  1809. HeightData.DataState := hdsNone;
  1810. HeightData.Owner.Data.UnlockList;
  1811. Exit;
  1812. end;
  1813. // ---Use linked HeightDataSource to prepare height data--
  1814. if HeightData.DataState = hdsQueued then
  1815. begin
  1816. HeightData.Owner.Data.LockList;
  1817. HeightData.DataState := hdsPreparing;
  1818. HeightData.Owner.Data.UnlockList;
  1819. end;
  1820. FHDS.StartPreparingData(HeightData);
  1821. if Assigned(FOnSourceDataFetched) then
  1822. FOnSourceDataFetched(self, HeightData);
  1823. if HeightData.DataState = hdsNone then
  1824. Exit;
  1825. if FActive then
  1826. PreparingData(HeightData);
  1827. inherited; // HeightData.DataState:=hdsReady;
  1828. end;
  1829. // ------------------------------------------------------------------
  1830. initialization
  1831. // ------------------------------------------------------------------
  1832. // class registrations
  1833. RegisterClasses([TGLBitmapHDS, TGLCustomHDS, TGLHeightDataSourceFilter]);
  1834. end.