GLHeightData.pas 61 KB

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