GLS.HeightData.pas 59 KB

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