GLS.RandomHDS.pas 91 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109
  1. //
  2. // This unit is part of the GLScene Engine, http://glscene.org
  3. //
  4. unit GLS.RandomHDS;
  5. (*
  6. This unit provides tools and objects to generate random Height Data Sources
  7. that can be used with TGLTerrainRenderer. General properties are defined in
  8. TGLBaseRandomHDS, but the main object is TGLCustomRandomHDS,
  9. which defines all the basic functionalities; however, it is an abstract class.
  10. So far, it has only one descendent, TGLFractalHDS, which implements the fractal
  11. middle-point displacement algorithm (aka plasma, aka diamond-square).
  12. The actual algorithms are independent functions called by the objects so they
  13. can also be used in other contexts. Basically, only the BuildHeightField
  14. method has to be overriden, and properties
  15. particular to the algorithm added (see TGLFractalHDS implementation). The
  16. BuildHeightField should contain a call to the algorithm function (or the algorithm
  17. itself, and MUST set the following fields: fSize, fMinHeight, fMaxHeight and
  18. fRangeHeight.
  19. Landscape generation consists in the following steps:
  20. 1° Generate height field
  21. 2° Modify it through erosion, sea surface, etc.
  22. 3° Compute light and shadows
  23. 4° Build the texture and assign it to a material created for this purpose
  24. The above classes generate isolated landscapes. They can be tiled in an
  25. infinite landscape through TGLTiledRndLandscape. The function of this class
  26. is to maintain a list of landscapes (called thereafter "landtiles"), to build
  27. and free them when needed.
  28. The TGLFractalArchipelago is an example of such a landscape generating an
  29. infinite landscape made of fractal islands.
  30. Although this structure may appear complex, the programmer just need to
  31. instanciate a TGLFractalArchipelago and to set its properties to get it running
  32. transparently. See the FractalLandscape and FractalArchipelago demos to see
  33. how to use these objects and what the various properties mean.
  34. Additional comments can be found in the code in the particular procedures.
  35. These components can be freely used. So far, you have to declare and
  36. create this component manually in your code and link it to a TGLTerrainRenderer.
  37. If you know how to make a registered component, please do it.
  38. *)
  39. interface
  40. uses
  41. Winapi.OpenGL,
  42. Winapi.Windows,
  43. System.Classes,
  44. System.Math,
  45. System.SysUtils,
  46. System.UITypes,
  47. System.Contnrs,
  48. Vcl.Graphics,
  49. Vcl.Imaging.jpeg,
  50. Vcl.Forms,
  51. OpenGLTokens,
  52. GLScene,
  53. GLVectorTypes,
  54. GLVectorGeometry,
  55. GLHeightData,
  56. GLTerrainRenderer,
  57. GLTexture,
  58. GLColor,
  59. GLCoordinates,
  60. GLRenderContextInfo,
  61. GLMaterial,
  62. GLContext;
  63. type
  64. TSeaErosion = record
  65. Enabled: boolean;
  66. BeachHeight: single;
  67. end;
  68. TRainErosion = record
  69. Enabled: boolean;
  70. ErosionRate: single;
  71. DepositRate: single;
  72. end;
  73. TLifeErosion = record
  74. Enabled: boolean;
  75. Robustness: single;
  76. end;
  77. TFractionErosion = record
  78. Enabled: boolean;
  79. Slope: single;
  80. end;
  81. TLandTileInfo = record
  82. x, z: integer; // Coordinates of the landtile. Used to generate the seed
  83. State: TGLHeightDataState; // Preparation status of the landtile
  84. end;
  85. TSteps = record
  86. Enabled: boolean;
  87. Count: integer;
  88. end;
  89. TMapOfSingle = array of array of single;
  90. TMapOfVector = array of array of TVector;
  91. TGLBaseRandomHDS = class;
  92. // Function type to use for topography-based texture
  93. TOnDrawTexture = function(const Sender: TGLBaseRandomHDS; x, y: integer; z: double; Normal: TVector): TColorVector of object;
  94. TSingleClamp = procedure(var x, y: single) of object;
  95. TIntegerClamp = procedure(var x, y: integer) of object;
  96. (* This class introduces all the basic properties of random landscape. No method
  97. implemented though. It is used as a descendant for
  98. - TGLCustomRandomLandscape: one tile landscape (cyclic or not)
  99. - TGLTiledRndLandscape: "infinite" landscapes (grids of TGLCustomRandomLandscape) *)
  100. TGLBaseRandomHDS = class(TGLHeightDataSource)
  101. private
  102. FSteps: TSteps;
  103. FLandCover: boolean;
  104. procedure SetOnDrawTexture(const Value: TOnDrawTexture);
  105. procedure SetSteps(const Value: TSteps);
  106. procedure SetLandCover(const Value: boolean);
  107. protected
  108. FSeed: integer;
  109. FSize: integer;
  110. FMaterialName: string;
  111. FLighting: boolean;
  112. FLightDirection: TVector;
  113. FTerrainRenderer: TGLTerrainRenderer;
  114. FLightColor: TColorVector;
  115. FShadows: boolean;
  116. FSea: boolean;
  117. FSeaLevel: single;
  118. FAmbientLight: single;
  119. FTaskProgress: integer;
  120. FTextureScale: integer;
  121. FErosionByFraction: TFractionErosion;
  122. FLightSmoothing: boolean;
  123. FCyclic: boolean;
  124. FSeaTransparency: single;
  125. FPrimerLandscape: boolean;
  126. FLandTileInfo: TLandTileInfo;
  127. FOnDrawTexture: TOnDrawTexture;
  128. function OnDrawTextureDefault(const Sender: TGLBaseRandomHDS; x, y: integer; z: double; Normal: TVector): TColorVector;
  129. procedure SetSeed(const Value: integer);
  130. procedure SetMaterialName(const Value: string);
  131. procedure SetLighting(const Value: boolean);
  132. procedure SetLightDirection(const Value: TVector);
  133. procedure SetTerrainRenderer(const Value: TGLTerrainRenderer); virtual; abstract;
  134. procedure SetLightColor(const Value: TColorVector);
  135. procedure SetShadows(const Value: boolean);
  136. procedure SetSea(const Value: boolean);
  137. procedure SetSeaLevel(const Value: single);
  138. procedure SetAmbientLight(const Value: single);
  139. procedure SetErosionByRain(const Value: TRainErosion);
  140. function GetErosionByRain: TRainErosion;
  141. procedure SetErosionBySea(const Value: TSeaErosion);
  142. procedure SetTextureScale(const Value: integer);
  143. procedure SetErosionByLife(const Value: TLifeErosion);
  144. procedure SetErosionByFraction(const Value: TFractionErosion);
  145. procedure SetLightSmoothing(const Value: boolean);
  146. procedure SetSeaTransparency(const Value: single);
  147. procedure SetPrimerLandscape(const Value: boolean);
  148. function GetSeaLevel: single;
  149. function GetSeaTransparency: single;
  150. procedure SetLandTileInfo(const Value: TLandTileInfo);
  151. function GetLandTileInfo: TLandTileInfo;
  152. procedure SetCyclic(const Value: boolean); virtual; abstract;
  153. public
  154. FErosionByRain: TRainErosion;
  155. FErosionBySea: TSeaErosion;
  156. FErosionByLife: TLifeErosion;
  157. constructor Create(AOwner: TComponent); override;
  158. destructor Destroy; override;
  159. // Usually white, but you can generate e.g.sunset ambiance by setting it to red
  160. property LightColor: TColorVector read FLightColor write SetLightColor;
  161. // Light is parallel (sun light)
  162. property LightDirection: TVector read FLightDirection write SetLightDirection;
  163. (* This function must be supplied by the user. Here he/she can define which
  164. colour to use depending on coordinates, elevation and normal. This provides
  165. a great flexibility. If no function is supplied (OnDrawTexture=nil), a default
  166. texture function is used (very basic, just blue and green). *)
  167. property OnDrawTexture: TOnDrawTexture read FOnDrawTexture write SetOnDrawTexture;
  168. published
  169. property AmbientLight: single read FAmbientLight write SetAmbientLight;
  170. (* If true, the landscape can be tiled to itself seamlessly.
  171. If false, the landscape is an isolated square. *)
  172. property Cyclic: boolean read FCyclic write SetCyclic;
  173. // Erosion parameters. See associated record types
  174. property ErosionByFraction: TFractionErosion read FErosionByFraction write SetErosionByFraction;
  175. property ErosionByLife: TLifeErosion read FErosionByLife write SetErosionByLife;
  176. property ErosionByRain: TRainErosion read FErosionByRain write SetErosionByRain;
  177. property ErosionBySea: TSeaErosion read FErosionBySea write SetErosionBySea;
  178. property LandCover: boolean read FLandCover write SetLandCover;
  179. // Enable or disable all lighting effects
  180. property Lighting: boolean read FLighting write SetLighting;
  181. // True by default. You can gain a little speed by disabling it.
  182. property LightSmoothing: boolean read FLightSmoothing write SetLightSmoothing;
  183. (* Not used *)
  184. property MaterialName: string read FMaterialName write SetMaterialName;
  185. (* If true, the height-field will not be emptied and generation will take the
  186. existing heights to shape the new landscape *)
  187. property PrimerLandscape: boolean read FPrimerLandscape write SetPrimerLandscape;
  188. // Enable the sea surface truncation
  189. property Sea: boolean read FSea write SetSea;
  190. // Sea level
  191. property SeaLevel: single read GetSeaLevel write SetSeaLevel;
  192. // Depth at which the sea bottom becomes invisible. See DoSea for more information
  193. property SeaTransparency: single read GetSeaTransparency write SetSeaTransparency;
  194. (* Seed used by the random generator. Each seed generate a different
  195. reproductible landscape. *)
  196. property Seed: integer read FSeed write SetSeed;
  197. // Enable shadow casting. May take some time for large Depth.
  198. property Shadows: boolean read FShadows write SetShadows;
  199. property Steps: TSteps read FSteps write SetSteps;
  200. // TerrainRenderer used to render the HDS.
  201. property TerrainRenderer: TGLTerrainRenderer read FTerrainRenderer write SetTerrainRenderer;
  202. (* Defines how many texture pixels are drawn per height-field cell. The larger
  203. this number the better the quality of the resulting image, but it takes a
  204. more time to compute. Good results are got between 1 and 5. *)
  205. property TextureScale: integer read FTextureScale write SetTextureScale;
  206. end;
  207. (* Base structure for all random landscape objects. It can't be used directly
  208. since its BuildHeightField procedure is abstract. Use one of its descendants instead. *)
  209. TGLCustomRandomHDS = class(TGLBaseRandomHDS)
  210. private
  211. FSlave: boolean;
  212. FMaxHeight: single;
  213. FMinHeight: single;
  214. FRangeHeight: single;
  215. FTask: string;
  216. FSingleConstrain: TSingleClamp;
  217. FIntegerConstrain: TIntegerClamp;
  218. FKeepNormals: boolean;
  219. function GetHeight(x, y: integer): single;
  220. procedure SetHeight(x, y: integer; const Value: single);
  221. procedure SetKeepNormals(const Value: boolean);
  222. protected
  223. procedure SetTerrainRenderer(const Value: TGLTerrainRenderer); override;
  224. procedure SetCyclic(const Value: boolean); override;
  225. procedure BoundaryClamp(var x, y: single); overload;
  226. procedure BoundaryClamp(var x, y: integer); overload;
  227. procedure CyclicClamp(var x, y: single); overload;
  228. procedure CyclicClamp(var x, y: integer); overload;
  229. // TGLTerrainRenderer event handler
  230. procedure GetTerrainBounds(var l, t, r, b: single);
  231. // This procedure MUST be called by the descendent of TGLBaseRandomHDS
  232. procedure SetSize(const aSize: integer);
  233. public
  234. FHeight: TMapOfSingle;
  235. FLightMap: TMapOfSingle;
  236. FNormal: TMapOfVector;
  237. // Upper bounds of the tile
  238. function BoundaryX: integer;
  239. function BoundaryZ: integer;
  240. // Generate the heightfield array, based on the topographical properties
  241. procedure BuildHeightField; overload; virtual; abstract;
  242. (* Provide an automated way to build a landscape. However, a greater control can
  243. be achieved by calling the various procedures manually (they are public methods)
  244. as one gets a sligthly different result depending on the sequence of erosion
  245. and sea steps. *)
  246. procedure BuildLandscape;
  247. (* - Compute the light effects
  248. - Compute the casted shadows
  249. - Perform a basic smoothing if TextureScale>1 *)
  250. procedure BuildLightMap; overload;
  251. procedure BuildLightMap(const aLightDirection: TVector); overload;
  252. // Normals are needed for lighting and slope-based textures
  253. procedure BuildNormals;
  254. (* For every pixel of the texture, computes slope and interpolated height and
  255. sends these information to a user-supplied function (OnDrawTexture), whose
  256. result is a tColorVector. If no OnDrawTexture is supplied, a basic default
  257. texture will be used. *)
  258. procedure BuildTexture;
  259. // Fill the heightfield with "Empty" values (-999)
  260. procedure ClearHeightField;
  261. // Fill the light map with 1
  262. procedure ClearLightMap;
  263. (* Constrain x,y to be in the boundaries of the height field array. This is
  264. done in two way depending on the kind of landscape:
  265. Cyclic landscapes: mod
  266. Non-cyclic landscape: clamp *)
  267. procedure ConstrainCoordinates(var x, y: single); overload;
  268. procedure ConstrainCoordinates(var x, y: integer); overload;
  269. constructor Create(AOwner: TComponent); override;
  270. destructor Destroy; override;
  271. // Enforces an identical height on the opposing edges of the landscape
  272. procedure DoCyclicBoundaries;
  273. (* Not yet implemented *)
  274. procedure DoErosionByFraction;
  275. (* Just a smoothing. Should be done last as it improves the look of other
  276. erosion effects. Too much biological erosion can ruin erase their results
  277. though. Some tweaking may be needed *)
  278. procedure DoErosionByLife;
  279. (* Create sharp valleys and canyons. If DepositRate>0, it will also fill the
  280. low pools, producing flat "lakes" and "ponds" *)
  281. procedure DoErosionByRain;
  282. // Create a beach and a cliff around the islands
  283. procedure DoErosionBySea;
  284. (* Cut all elevations lower than sea level. If Transparency>0, the sea surface
  285. will not be flat, but a slight elevation change (unperceptible in 3D view)
  286. allow to fake transparency in the OnDrawTexture. *)
  287. procedure DoSea;
  288. // Discretise the heigthfield in a chosen number of steps
  289. procedure DoSteps;
  290. (* x and y are range-checked and constrained into the array. This slows down
  291. computation. If you don't need to range-check (this is mainly useful in
  292. cyclic landscapes when you need a seamless joint), call fHeigth instead
  293. (this is a protected field, therefore only accessible from TGLFractalHDS
  294. descendents. *)
  295. property Heights[x, y: integer]: single read GetHeight write SetHeight;
  296. // Range checked
  297. (* A specific implementation of THeightDataSource.InterpolatedHeight *)
  298. function Interpolate(x, y: single): single;
  299. // Keep the array of normals for future use
  300. property KeepNormals: boolean read FKeepNormals write SetKeepNormals;
  301. (* Property used by TGLTiledRndLandscape to know where the landtile is located
  302. and other parameters. See tLandTileInfo *)
  303. property LandTileInfo: TLandTileInfo read GetLandTileInfo write SetLandTileInfo;
  304. // Range checking
  305. function PointInMap(const x, y: single): boolean; overload;
  306. function PointInMap(const x, y: integer): boolean; overload;
  307. // Store the minimum and maximum elevations
  308. property MaxHeight: single read FMaxHeight;
  309. property MinHeight: single read FMinHeight;
  310. // Vector normal to the terrain at the position
  311. function Normal(const Position: TVector): TVector;
  312. // Max height - min height
  313. property RangeHeight: single read FRangeHeight;
  314. (* Scale of the Terrain Renderer. They are set so as giving a identical
  315. vertical/horitontal ratio with any size. Therefore, Scale.X=Scale.Y=1 and
  316. only Scale.Z varies. If you want to increase the landscape scale, the best way
  317. would be to place the Terrain Renderer in a DummyCube and rescale it. *)
  318. function Scale: TGLCoordinates;
  319. (* Size of the square height array. With the middle-point algorithm, it is always
  320. Size = 2^N+1. In a cyclic landscape, the last row and columns are identical
  321. to the first. *)
  322. property Size: integer read FSize;
  323. // A height rescaled between 0 and 1000 for
  324. function StandardisedHeight(const x, y: integer): single;
  325. (* When long computations are running, this property contains the operation
  326. beeing processed. *)
  327. property Task: string read FTask;
  328. // A value between 0 and 100 indicating the percentage of completion
  329. property TaskProgress: integer read FTaskProgress;
  330. // Use these boundaries with non-cyclic landscapes to constrain camera movements.
  331. function XMoveBoundary: single;
  332. function ZMoveBoundary: single;
  333. // tTerrainRender event handler
  334. procedure StartPreparingData(heightData: TGLHeightData); override;
  335. published
  336. property Cyclic: boolean read FCyclic write SetCyclic;
  337. end;
  338. // Random landscape based on the middle-point displacement algorithm
  339. TGLFractalHDS = class(TGLCustomRandomHDS)
  340. private
  341. FAmplitude: integer;
  342. FDepth: integer;
  343. FRoughness: single;
  344. procedure SetAmplitude(const Value: integer);
  345. procedure SetDepth(const Value: integer);
  346. procedure SetRoughness(const Value: single);
  347. public
  348. procedure BuildHeightField; overload; override;
  349. procedure BuildHeightField(const aDepth, aSeed, aAmplitude: integer); overload;
  350. constructor Create(AOwner: TComponent); override;
  351. published
  352. // Proportional to the difference between highest and lowest altitude.
  353. property Amplitude: integer read fAmplitude write SetAmplitude;
  354. (* Number of levels in the fractal process. Depth defines the size of the
  355. landscape: Size = 2^Depth+1 . Good results are got with Depth>=6. Above 10
  356. the landscape takes a lot of time to be generated. *)
  357. property Depth: integer read fDepth write SetDepth;
  358. // The lower this parameter, the smoother the landscape. Takes value between 0 and 1
  359. property Roughness: single read fRoughness write SetRoughness;
  360. end;
  361. (* TMapOfLandscapes :array of array of TGLBaseRandomHDS; *)
  362. TGLLandTile = TGLCustomRandomHDS;
  363. TRelativeCoordinate = record
  364. DX, DZ: integer
  365. end;
  366. TOnCreateLandTile = procedure(x, z, Seed: integer; var aLandscape: TGLLandTile) of object;
  367. TIsDefaultTile = function(X, Z: integer): boolean of object;
  368. TGLTiledRndLandscape = class(TGLBaseRandomHDS)
  369. private
  370. FLandTileComputing: boolean; // Is a landtile being computed?
  371. FExtentX: integer;
  372. FExtentZ: integer;
  373. FExtentXhalf: integer;
  374. FExtentZhalf: integer;
  375. fLandTileSize: integer;
  376. FSingleConstrain: TSingleClamp;
  377. FIntegerConstrain: TIntegerClamp;
  378. FTerrainRenderer: TGLTerrainRenderer;
  379. FCamera: TGLCamera;
  380. fOnCreateLandTile: TOnCreateLandTile;
  381. fOnCreateDefaultTile: TStartPreparingDataEvent;
  382. FIsDefaultTile: TIsDefaultTile;
  383. FSeed: integer;
  384. fBaseSeed: integer;
  385. fComputedLandTile: TGLLandTile;
  386. FLandTileCapacity: integer;
  387. FGenerationRadius: integer;
  388. FLandTileDensity: single;
  389. procedure fDefaultOnCreateDefaultTile(heightData: TGLHeightData);
  390. function fDefaultIsDefaultTile(x, z: integer): boolean;
  391. procedure SetExtentX(const Value: integer);
  392. procedure SetExtentZ(const Value: integer);
  393. procedure SetOnCreateLandTile(const Value: TOnCreateLandTile);
  394. procedure SetCamera(const Value: TGLCamera);
  395. procedure SetIsDefaultTile(const Value: TIsDefaultTile);
  396. procedure SetSeed(const Value: integer);
  397. procedure SetOnCreateDefaultTile(const Value: TStartPreparingDataEvent);
  398. function GetTask: string;
  399. function GetTaskProgress: integer;
  400. procedure SetLandTileCapacity(const Value: integer);
  401. procedure SetGenerationRadius(const Value: integer);
  402. procedure SetLandTileDensity(const Value: single);
  403. protected
  404. FGenRadius: array of TRelativeCoordinate;
  405. FOldCamX: integer;
  406. FOldCamZ: integer;
  407. FMapUpdating: boolean;
  408. FLandTiles: tComponentList;
  409. procedure BoundaryClamp(var x, z: single); overload;
  410. procedure BoundaryClamp(var x, z: integer); overload;
  411. procedure ComputeLandTile(const aX, aZ: integer; var NewLandTile: TGLLandTile); virtual;
  412. procedure CyclicClamp(var x, z: single); overload;
  413. procedure CyclicClamp(var x, z: integer); overload;
  414. // tTerrainRenderer event handler
  415. procedure GetTerrainBounds(var l, t, r, b: single);
  416. function LandTileSeed(x, z: integer): integer;
  417. property OnCreateDefaultTile: TStartPreparingDataEvent read fOnCreateDefaultTile write SetOnCreateDefaultTile;
  418. procedure SetCyclic(const Value: boolean); override;
  419. // This procedure MUST be called by the descendent of TGLRandomArchipelago
  420. procedure SetSize(const aSize: integer);
  421. function fSortLandscapes(Item1, Item2: Pointer): integer;
  422. // procedure PrepareLandTileData(HeightData:tHeightData; LandTile:tLandTile);
  423. (* tTerrainRender event handler *)
  424. procedure SetTerrainRenderer(const Value: TGLTerrainRenderer); override;
  425. public
  426. procedure ApplyLighting(var aLandTile: TGLLandTile);
  427. procedure ApplyTexture(var aLandTile: TGLLandTile);
  428. procedure ApplyTopography(var aLandTile: TGLLandTile);
  429. procedure CameraPosition(var TileX, TileZ: integer);
  430. procedure CleanUp;
  431. (* Constrain x,y to be in the boundaries of the height field array. This is
  432. done in two way depending on the kind of landscape:
  433. Cyclic landscapes: mod
  434. Non-cyclic landscape: clamp *)
  435. procedure ConstrainCoordinates(var x, z: single); overload;
  436. procedure ConstrainCoordinates(var x, z: integer); overload;
  437. constructor Create(AOwner: TComponent); override;
  438. destructor Destroy; override;
  439. // Compute the landtile containing (x,z)
  440. procedure FindLandTile(const x, z: single; var TileX, TileZ: integer);
  441. // Build the first landtile and position the camera. Must be called first.
  442. procedure Initialize(const aX, aZ: single); virtual;
  443. (* User-supplied function determining if this landtile will be built by the
  444. OnCreateDefaultTile or if a landscape will be generated. *)
  445. property IsDefaultTile: TIsDefaultTile read FIsDefaultTile write SetIsDefaultTile;
  446. // Number of landtile in memory
  447. function LandtileCount: integer;
  448. // Size of a landtile. Must be a power of two
  449. property LandTileSize: integer read fLandTileSize;
  450. (* User-specified event handler containing the particular code for tile generation *)
  451. property OnCreateLandTile: TOnCreateLandTile read fOnCreateLandTile write SetOnCreateLandTile;
  452. (* When long computations are running, this property contains the operation
  453. beeing processed. *)
  454. property Task: string read GetTask;
  455. // A value between 0 and 100 indicating the percentage of completion
  456. property TaskProgress: integer read GetTaskProgress;
  457. // Distance between two landtiles
  458. function TileDistance(const x1, z1, x2, z2: integer): single;
  459. (* Square of distance between two landtiles. Use this function to compare
  460. two distances. *)
  461. function TileDistanceSquared(const x1, z1, x2, z2: integer): integer;
  462. (* This procedure check which landtiles must be generated or destroyed as a
  463. function of camera position. This is let to the descendent classes. *)
  464. procedure Update;
  465. property MapUpdating: boolean read fMapUpdating;
  466. // Use these boundaries with non-cyclic landscapes to constrain camera movements.
  467. function XMoveBoundary: single;
  468. function ZMoveBoundary: single;
  469. procedure StartPreparingData(heightData: TGLHeightData); override;
  470. published
  471. property Camera: TGLCamera read FCamera write SetCamera;
  472. property Cyclic: boolean read FCyclic write SetCyclic;
  473. (* Dimensions of the "infinite" landscape. Can be set very high. These parameters
  474. have neither memory nor speed consequence. They are mainly used to compute
  475. a unique seed for each landtile *)
  476. property ExtentX: integer read FExtentX write SetExtentX;
  477. property ExtentZ: integer read FExtentZ write SetExtentZ;
  478. { Distance at which a new landtile begin to be built. Increasing this value
  479. allows for a higher camera speed but it will also increase the memory requirements. }
  480. property GenerationRadius: integer read FGenerationRadius write SetGenerationRadius;
  481. // Number of landtile to keep in memory. Should not be modified.
  482. property LandTileCapacity: integer read FLandTileCapacity write SetLandTileCapacity;
  483. // Probability that a given landtile is non-default
  484. property LandTileDensity: single read FLandTileDensity write SetLandTileDensity;
  485. // Base seed for the entire archipelago
  486. property Seed: integer read FSeed write SetSeed;
  487. // Terrain renderer linked to the HDS. Must be set just after creation.
  488. property TerrainRenderer: TGLTerrainRenderer read FTerrainRenderer write SetTerrainRenderer;
  489. end;
  490. TGLFractalArchipelago = class(TGLTiledRndLandscape)
  491. private
  492. FDepth: integer;
  493. FRoughnessMax: single;
  494. FRoughnessMin: single;
  495. FAmplitudeMin: integer;
  496. FAmplitudeMax: integer;
  497. FSeaDynamic: boolean;
  498. FSeaMaterialName: string;
  499. FWaveAmplitude: single;
  500. FWaveSpeed: single;
  501. function GetIslandDensity: single;
  502. (* PostRender event handler drawing a static water plane between islands
  503. Code borrowed from Eric's Archipelago GLScene advanced demo *)
  504. procedure FPostRenderSeaStatic(var rci: TGLRenderContextInfo; var HeightDatas: TList);
  505. // Sea with waves. Borrowed from GLS Archipelago advanced demo
  506. procedure FPostRenderSeaDynamic(var rci: TGLRenderContextInfo; var HeightDatas: TList);
  507. procedure SetIslandDensity(const Value: single);
  508. procedure SetDepth(const Value: integer);
  509. procedure SetRoughnessMax(const Value: single);
  510. procedure SetRoughnessMin(const Value: single);
  511. procedure SetAmplitudeMax(const Value: integer);
  512. procedure SetAmplitudeMin(const Value: integer);
  513. procedure SetSeaDynamic(const Value: boolean);
  514. procedure SetSeaMaterialName(const Value: string);
  515. procedure SetWaveAmplitude(const Value: single);
  516. procedure SetWaveSpeed(const Value: single);
  517. protected
  518. procedure SetTerrainRenderer(const Value: TGLTerrainRenderer); override;
  519. procedure fOnCreateLandTile(aX, aZ, aSeed: integer; var aLandscape: TGLLandTile);
  520. procedure fOnCreateDefaultTile(heightData: TGLHeightData);
  521. public
  522. procedure ComputeLandTile(const aX, aZ: integer; var NewLandTile: TGLLandTile); override;
  523. constructor Create(AOwner: TComponent); override;
  524. published
  525. // Ranges for the amplitude parameter in the fractal algorithm
  526. property AmplitudeMax: integer read FAmplitudeMax write SetAmplitudeMax;
  527. property AmplitudeMin: integer read FAmplitudeMin write SetAmplitudeMin;
  528. // Depth of the fractal algorithm
  529. property Depth: integer read fDepth write SetDepth;
  530. (* A wrapper for LandtileDensity. This is the probabilty for a landtile to
  531. contain an island. *)
  532. property IslandDensity: single read GetIslandDensity write SetIslandDensity;
  533. // Ranges for the roughness parameter in the fractal algorithm
  534. property RoughnessMax: single read FRoughnessMax write SetRoughnessMax;
  535. property RoughnessMin: single read FRoughnessMin write SetRoughnessMin;
  536. // If true, the sea will show dynamic waves. Slow.
  537. property SeaDynamic: boolean read FSeaDynamic write SetSeaDynamic;
  538. (* Reference to a material in the TerrainRenderer's material library. This
  539. material will be used to drape the water plane. *)
  540. property SeaMaterialName: string read FSeaMaterialName write SetSeaMaterialName;
  541. // Size of the waves
  542. property WaveAmplitude: single read FWaveAmplitude write SetWaveAmplitude;
  543. property WaveSpeed: single read FWaveSpeed write SetWaveSpeed;
  544. end;
  545. (* Texture functions *)
  546. function LoadJPGtexture(const JpgName: string): tBitmap;
  547. function NoisyColor(const Color: tColor; const Noise: single = 0.05): TColorVector;
  548. function TextureGreen(const x, y: integer): TColorVector;
  549. function TextureBlue(const x, y: integer): TColorVector;
  550. function TextureSand(const x, y: integer): TColorVector;
  551. function TextureBrownSoil(const x, y: integer): TColorVector;
  552. function TextureDarkGreen(const x, y: integer): TColorVector;
  553. function TextureDarkGray(const x, y: integer): TColorVector;
  554. function TextureWhite(const x, y: integer): TColorVector;
  555. (* Random HDS functions *)
  556. procedure FractalMiddlePointHDS(const aDepth, aSeed, aAmplitude: integer; const aRoughness: single; aCyclic: boolean;
  557. var z: TMapOfSingle; var MinZ, MaxZ: single);
  558. procedure InitializeRandomGenerator(const Seed: integer);
  559. (* Landscape primers *)
  560. procedure PrimerNull(var z: TMapOfSingle);
  561. procedure PrimerIsland(LowZ, HighZ: single; var z: TMapOfSingle);
  562. const
  563. VerticalScalingFactor = 128;
  564. // ==========================================================================
  565. implementation
  566. // ==========================================================================
  567. const // Neighbourhood vectors and weight
  568. NeighX: array [0 .. 8] of integer = (-1, 0, 1, 1, 1, 0, -1, -1, 0);
  569. NeighY: array [0 .. 8] of integer = (-1, -1, -1, 0, 1, 1, 1, 0, 0);
  570. NeighW: array [0 .. 8] of single = (1 / 1.4142, 1, 1 / 1.4142, 1, 1 / 1.4142, 1, 1 / 1.4142, 1, 2);
  571. SumWeights = 4 / 1.4142 + 4 + 2;
  572. Empty: single = -999;
  573. VSF = VerticalScalingFactor;
  574. var
  575. rhdsStartTime: cardinal;
  576. rhdsLandscapeCounter: cardinal = 0;
  577. // Counter :tTickCounter;
  578. function LoadJPGtexture(const JpgName: string): tBitmap;
  579. var
  580. Jpg: TJPEGImage;
  581. begin
  582. Result := tBitmap.Create;
  583. Jpg := TJPEGImage.Create;
  584. Jpg.LoadFromFile(JpgName);
  585. Result.Assign(Jpg);
  586. Jpg.Free;
  587. end;
  588. function NoisyColor(const Color: tColor; const Noise: single = 0.05): TColorVector;
  589. var
  590. r: single;
  591. begin
  592. Result := ConvertWinColor(Color);
  593. r := random * Noise;
  594. AddVector(Result, r);
  595. end;
  596. function TextureSand(const x, y: integer): TColorVector;
  597. begin
  598. Result := NoisyColor($0071D8FF);
  599. end;
  600. function TextureBrownSoil(const x, y: integer): TColorVector;
  601. begin
  602. Result := NoisyColor($00008BBF);
  603. end;
  604. function TextureDarkGreen(const x, y: integer): TColorVector;
  605. begin
  606. Result := NoisyColor($00004000);
  607. end;
  608. function TextureDarkGray(const x, y: integer): TColorVector;
  609. begin
  610. Result := NoisyColor(clDkGray);
  611. end;
  612. function TextureWhite(const x, y: integer): TColorVector;
  613. begin
  614. Result := NoisyColor(clWhite);
  615. end;
  616. function TextureBlue(const x, y: integer): TColorVector;
  617. begin
  618. Result := NoisyColor(clBlue);
  619. end;
  620. function TextureGreen(const x, y: integer): TColorVector;
  621. begin
  622. Result := NoisyColor(clGreen);
  623. end;
  624. procedure InitializeRandomGenerator(const Seed: integer);
  625. var
  626. i: integer;
  627. begin
  628. RandSeed := Seed;
  629. for i := 1 to 50 do
  630. random; // Pre-heat the generator
  631. end;
  632. //-----------------------------------
  633. // TGLBaseRandomHDS
  634. //-----------------------------------
  635. constructor TGLBaseRandomHDS.Create(AOwner: TComponent);
  636. begin
  637. inherited;
  638. Inc(rhdsLandscapeCounter);
  639. Name := Format('RandomLandscape%d', [rhdsLandscapeCounter]);
  640. FLightColor := VectorMake(1, 1, 1);
  641. FLightDirection := VectorMake(-1, 0, -1);
  642. FAmbientLight := 0.5;
  643. FTextureScale := 1;
  644. FMaterialName := '';
  645. FLighting := True;
  646. FLightSmoothing := True;
  647. Cyclic := True;
  648. FSeed := RandSeed;
  649. FSeaLevel := 0.0;
  650. FErosionBySea.BeachHeight := 0.01;
  651. FErosionBySea.Enabled := False;
  652. FErosionByRain.Enabled := True;
  653. FErosionByRain.ErosionRate := 0.5;
  654. FErosionByRain.DepositRate := FErosionByRain.ErosionRate;
  655. FErosionByLife.Enabled := True;
  656. FErosionByLife.Robustness := 1;
  657. FLandTileInfo.State := hdsNone;
  658. end;
  659. destructor TGLBaseRandomHDS.Destroy;
  660. begin
  661. inherited;
  662. end;
  663. function TGLBaseRandomHDS.GetSeaLevel: single;
  664. begin
  665. Result := FSeaLevel / VSF; // factor used in tTerrainRender
  666. end;
  667. function TGLBaseRandomHDS.GetSeaTransparency: single;
  668. begin
  669. Result := FSeaTransparency / VSF; // factor used in tTerrainRender
  670. end;
  671. function TGLBaseRandomHDS.GetErosionByRain: TRainErosion;
  672. begin
  673. Result := FErosionByRain;
  674. end;
  675. function TGLBaseRandomHDS.GetLandTileInfo: TLandTileInfo;
  676. begin
  677. Result := FLandTileInfo;
  678. end;
  679. function TGLBaseRandomHDS.OnDrawTextureDefault(const Sender: TGLBaseRandomHDS; x, y: integer; z: double; Normal: TVector)
  680. : TColorVector;
  681. begin
  682. if z > Sender.SeaLevel * VSF then
  683. Result := TextureGreen(x, y)
  684. else
  685. Result := TextureBlue(x, y);
  686. end;
  687. procedure TGLBaseRandomHDS.SetAmbientLight(const Value: single);
  688. begin
  689. FAmbientLight := Value;
  690. end;
  691. procedure TGLBaseRandomHDS.SetErosionByFraction(const Value: TFractionErosion);
  692. begin
  693. FErosionByFraction := Value;
  694. end;
  695. procedure TGLBaseRandomHDS.SetErosionByLife(const Value: TLifeErosion);
  696. begin
  697. FErosionByLife := Value;
  698. end;
  699. procedure TGLBaseRandomHDS.SetErosionByRain(const Value: TRainErosion);
  700. begin
  701. FErosionByRain := Value;
  702. end;
  703. procedure TGLBaseRandomHDS.SetErosionBySea(const Value: TSeaErosion);
  704. begin
  705. FErosionBySea := Value;
  706. end;
  707. procedure TGLBaseRandomHDS.SetLandCover(const Value: boolean);
  708. begin
  709. FLandCover := Value;
  710. end;
  711. procedure TGLBaseRandomHDS.SetLandTileInfo(const Value: TLandTileInfo);
  712. begin
  713. FLandTileInfo := Value;
  714. end;
  715. procedure TGLBaseRandomHDS.SetLightColor(const Value: TColorVector);
  716. begin
  717. FLightColor := Value;
  718. end;
  719. procedure TGLBaseRandomHDS.SetLightDirection(const Value: TVector);
  720. var
  721. v: TVector;
  722. begin
  723. v := Value;
  724. NormalizeVector(v);
  725. FLightDirection := Value;
  726. end;
  727. procedure TGLBaseRandomHDS.SetLighting(const Value: boolean);
  728. begin
  729. FLighting := Value;
  730. end;
  731. procedure TGLBaseRandomHDS.SetLightSmoothing(const Value: boolean);
  732. begin
  733. FLightSmoothing := Value;
  734. end;
  735. procedure TGLBaseRandomHDS.SetMaterialName(const Value: string);
  736. begin
  737. FMaterialName := Value;
  738. end;
  739. procedure TGLBaseRandomHDS.SetOnDrawTexture(const Value: TOnDrawTexture);
  740. begin
  741. if @Value <> nil then
  742. FOnDrawTexture := Value
  743. else
  744. FOnDrawTexture := OnDrawTextureDefault; // Basic texture event
  745. end;
  746. procedure TGLBaseRandomHDS.SetPrimerLandscape(const Value: boolean);
  747. begin
  748. FPrimerLandscape := Value;
  749. end;
  750. procedure TGLBaseRandomHDS.SetSea(const Value: boolean);
  751. begin
  752. FSea := Value;
  753. end;
  754. procedure TGLBaseRandomHDS.SetSeaLevel(const Value: single);
  755. begin
  756. FSeaLevel := Value * VSF; // factor used in tTerrainRender
  757. end;
  758. procedure TGLBaseRandomHDS.SetSeaTransparency(const Value: single);
  759. begin
  760. FSeaTransparency := Value * VSF; // factor used in tTerrainRender
  761. end;
  762. procedure TGLBaseRandomHDS.SetSeed(const Value: integer);
  763. begin
  764. FSeed := Value;
  765. end;
  766. procedure TGLBaseRandomHDS.SetShadows(const Value: boolean);
  767. begin
  768. FShadows := Value;
  769. end;
  770. procedure TGLBaseRandomHDS.SetSteps(const Value: TSteps);
  771. begin
  772. FSteps := Value;
  773. end;
  774. procedure TGLBaseRandomHDS.SetTextureScale(const Value: integer);
  775. begin
  776. FTextureScale := Value;
  777. end;
  778. //
  779. // TGLCustomRandomHDS
  780. //
  781. procedure TGLCustomRandomHDS.BoundaryClamp(var x, y: single);
  782. begin
  783. ClampValue(x, 0, FSize);
  784. ClampValue(y, 0, FSize);
  785. end;
  786. procedure TGLCustomRandomHDS.BoundaryClamp(var x, y: integer);
  787. begin
  788. if x < 0 then
  789. x := 0
  790. else if x > FSize then
  791. x := FSize;
  792. if y < 0 then
  793. y := 0
  794. else if y > FSize then
  795. y := FSize;
  796. end;
  797. function TGLCustomRandomHDS.BoundaryX: integer;
  798. begin
  799. Result := Round(FSize * Scale.x);
  800. end;
  801. function TGLCustomRandomHDS.BoundaryZ: integer;
  802. begin
  803. Result := Round(FSize * Scale.z);
  804. end;
  805. procedure TGLCustomRandomHDS.BuildLandscape;
  806. begin
  807. FTask := 'Landscape generation';
  808. FTaskProgress := 0;
  809. // Empty all height-field cells
  810. if not FPrimerLandscape then
  811. ClearHeightField;
  812. (* Build the basic fractal height field. It is mandatory and must always be
  813. called first. *)
  814. BuildHeightField;
  815. (* Various operations that reshape the height field. These procedures may be
  816. called in any order, although the one proposed here is the most natural.
  817. These procedures are optional *)
  818. if FErosionByRain.Enabled then
  819. DoErosionByRain;
  820. if FErosionByLife.Enabled then
  821. DoErosionByLife;
  822. if FErosionBySea.Enabled then
  823. DoErosionBySea;
  824. if FSteps.Enabled then
  825. DoSteps;
  826. (* Doing sea first would speeds up the following processes
  827. but the result would be slightly less realistic. In
  828. particular with transparency, you can have a nice effect
  829. of submarine valleys prolungating land canyons.
  830. This procedure is optional *)
  831. if FSea then
  832. DoSea;
  833. if FCyclic then
  834. DoCyclicBoundaries; // Ensures a seamless fit
  835. // Compute a normal for each vertex. Used by BuildLightMap and BuildTexture
  836. if FLandCover then
  837. BuildNormals;
  838. (* Add light effects. Either BuildLightMap or ClearLigthMap must be called.
  839. Used by BuildTexture. *)
  840. if FLighting and LandCover then
  841. BuildLightMap
  842. else
  843. ClearLightMap;
  844. (* Builds the actual texture. If it is not used, the terrain will be textured
  845. with its Material, if defined. *)
  846. if FLandCover then
  847. BuildTexture;
  848. { Free memory. If you need often to recompute texture, you may want to keep
  849. one or both maps, providing the heightfield or the light source have not changed. }
  850. if not FKeepNormals then
  851. FNormal := nil;
  852. FLightMap := nil;
  853. FTask := ' Updating terrain renderer';
  854. FTaskProgress := 0;
  855. Application.ProcessMessages;
  856. MarkDirty;
  857. // Tells the HDS that changes have been made (don't forget it or you'll get strange things)
  858. end;
  859. procedure TGLCustomRandomHDS.BuildLightMap;
  860. var
  861. i, j, k, m, n: integer;
  862. x, y: single;
  863. t: single;
  864. v1, v2: TVector;
  865. l: TVector;
  866. Shade: single;
  867. begin
  868. if FSize = 0 then
  869. exit;
  870. FTask := 'Light-map computation';
  871. FTaskProgress := 0;
  872. SetLength(FLightMap, (FSize + 1) * TextureScale, (FSize + 1) * TextureScale);
  873. l := FLightDirection;
  874. NormalizeVector(l);
  875. NegateVector(l);
  876. { Compute lighting }
  877. for i := 0 to FSize do
  878. begin
  879. FTaskProgress := Round(i / FSize * 100);
  880. for j := 0 to FSize do
  881. begin
  882. Application.ProcessMessages;
  883. Shade := abs(VectorDotProduct(FNormal[i, j], l));
  884. ClampValue(Shade, 0);
  885. for k := i * TextureScale to (i + 1) * TextureScale - 1 do
  886. for n := j * TextureScale to (j + 1) * TextureScale - 1 do
  887. FLightMap[k, n] := Shade;
  888. end; // for
  889. end; // for i
  890. { Shadows }
  891. if FShadows then
  892. begin
  893. FTask := 'Shadow casting';
  894. FTaskProgress := 0;
  895. l.x := l.x * Scale.x;
  896. l.y := l.y * VSF / Scale.y;
  897. l.z := l.z * Scale.z;
  898. for j := 0 to FSize do
  899. begin
  900. FTaskProgress := Round(j / FSize * 100);
  901. for i := 0 to FSize do
  902. begin
  903. if FLightMap[i * TextureScale, j * TextureScale] > 0 then
  904. begin // Don't look for shadow if the point is already shadowed
  905. v1 := VectorMake(i, FHeight[i, j], j); // Starting point
  906. for k := 2 to Round(FSize * 1.4) do
  907. begin // Quick and dirty ray-casting
  908. v2 := VectorCombine(v1, l, 1, k);
  909. // Casts a ray in direction of the sun
  910. x := Round(v2.x);
  911. y := Round(v2.z);
  912. if Interpolate(x, y) > v2.y then
  913. begin
  914. Application.ProcessMessages;
  915. for m := i * TextureScale to (i + 1) * TextureScale - 1 do
  916. for n := j * TextureScale to (j + 1) * TextureScale - 1 do
  917. FLightMap[m, n] := 0;
  918. break; // Shadow caster found. No need to continue
  919. end; // if
  920. end; // for k
  921. end; // if
  922. end; // for j
  923. end; // for i
  924. end; // if
  925. { Smoothing }
  926. if FLightSmoothing then
  927. begin
  928. FTask := 'Light-map smoothing';
  929. FTaskProgress := 0;
  930. for m := 1 to TextureScale - 1 do
  931. begin
  932. FTaskProgress := Round(m / TextureScale * 100);
  933. for j := 1 to High(FLightMap) - 1 do
  934. begin
  935. for i := 1 to High(FLightMap) - 1 do
  936. begin
  937. Application.ProcessMessages;
  938. t := 0;
  939. for k := 0 to 8 do
  940. begin
  941. t := t + FLightMap[i + NeighX[k], j + NeighY[k]] * NeighW[k];
  942. end; // for k
  943. FLightMap[i, j] := t / SumWeights;
  944. end; // for j
  945. end; // for i
  946. end; // for m
  947. end; // if
  948. end;
  949. procedure TGLCustomRandomHDS.BuildLightMap(const aLightDirection: TVector);
  950. begin
  951. FLightDirection := aLightDirection;
  952. BuildLightMap;
  953. end;
  954. procedure TGLCustomRandomHDS.BuildNormals;
  955. var
  956. i, j: integer;
  957. z0: single;
  958. v1, v2: TVector;
  959. n1: TVector;
  960. Normal: TVector;
  961. begin
  962. FTask := 'Normal computation';
  963. for i := 0 to FSize do
  964. begin
  965. FTaskProgress := Round(i / FSize * 100);
  966. for j := 0 to FSize do
  967. begin
  968. Application.ProcessMessages;
  969. z0 := FHeight[i, j];
  970. Normal := NullHmgVector;
  971. MakeVector(v1, Scale.x, (Heights[i + 1, j] - z0) * Scale.y / VSF, 0);
  972. MakeVector(v2, 0, (Heights[i, j + 1] - z0) * Scale.y / VSF, Scale.z);
  973. Normal := VectorCrossProduct(v2, v1);
  974. NormalizeVector(Normal);
  975. MakeVector(v1, -Scale.x, (Heights[i - 1, j] - z0) * Scale.y / VSF, 0);
  976. MakeVector(v2, 0, (Heights[i, j + 1] - z0) * Scale.y / VSF, Scale.z);
  977. n1 := VectorCrossProduct(v1, v2);
  978. NormalizeVector(n1);
  979. Normal := VectorAdd(Normal, n1);
  980. MakeVector(v1, -Scale.x, (Heights[i - 1, j] - z0) * Scale.y / VSF, 0);
  981. MakeVector(v2, 0, (Heights[i, j - 1] - z0) * Scale.y / VSF, -Scale.z);
  982. n1 := VectorCrossProduct(v2, v1);
  983. NormalizeVector(n1);
  984. Normal := VectorAdd(Normal, n1);
  985. MakeVector(v1, Scale.x, (Heights[i + 1, j] - z0) * Scale.y / VSF, 0);
  986. MakeVector(v2, 0, (Heights[i, j - 1] - z0) * Scale.y / VSF, -Scale.z);
  987. n1 := VectorCrossProduct(v1, v2);
  988. NormalizeVector(n1);
  989. Normal := VectorAdd(Normal, n1);
  990. FNormal[i, j] := VectorScale(Normal, 0.25);
  991. // Average of the 4 adjacent normals
  992. end; // for j
  993. end; // for i
  994. end;
  995. procedure TGLCustomRandomHDS.BuildTexture;
  996. type
  997. pRGBTripleArray = ^TRGBTripleArray;
  998. TRGBTripleArray = array [word] of TRGBTriple;
  999. var
  1000. Bmp: array of array of tBitmap;
  1001. x0, y0: integer;
  1002. xx, yy: integer;
  1003. x, y: integer;
  1004. nbTiles: integer;
  1005. Side: integer;
  1006. meancol: tColor;
  1007. Line: pRGBTripleArray;
  1008. function MeanColor(color1, color2: tColor): tColor;
  1009. var
  1010. r1, g1, b1: Byte;
  1011. r2, g2, b2: Byte;
  1012. begin
  1013. r1 := (color1 and $000000FF);
  1014. g1 := ((color1 and $0000FF00) shr 8);
  1015. b1 := ((color1 and $00FF0000) shr 16);
  1016. r2 := (color2 and $000000FF);
  1017. g2 := ((color2 and $0000FF00) shr 8);
  1018. b2 := ((color2 and $00FF0000) shr 16);
  1019. Result := RGB((r1 + r2) div 2, (g1 + g2) div 2, (b1 + b2) div 2);
  1020. end;
  1021. procedure MakeRGBTriple(const Color: TColorVector; var RGBTriple: TRGBTriple);
  1022. begin
  1023. with RGBTriple do
  1024. begin
  1025. rgbtRed := Round(Color.x * 255);
  1026. rgbtGreen := Round(Color.y * 255);
  1027. rgbtBlue := Round(Color.z * 255);
  1028. end; // with
  1029. end;
  1030. function ComputePixel(const x, y: integer): TRGBTriple;
  1031. var
  1032. i, j: integer;
  1033. Shade: TColorVector;
  1034. Cover: TColorVector;
  1035. z: double;
  1036. begin
  1037. i := (x0 + x) div TextureScale;
  1038. j := (y0 + y) div TextureScale;
  1039. z := Interpolate((x0 + x) / TextureScale, (y0 + y) / TextureScale);
  1040. Application.ProcessMessages;
  1041. { Cover:=OnDrawTexture(Self,FLandTileInfo.x*fSize+x0+x,
  1042. FLandTileInfo.z*fSize+y0+y,z,fNormal[i,j]); }
  1043. Cover := OnDrawTexture(Self, x0 + x, y0 + y, z, FNormal[i, j]);
  1044. Application.ProcessMessages;
  1045. Shade := VectorScale(FLightColor, FLightMap[x0 + x, y0 + y]);
  1046. Application.ProcessMessages;
  1047. ScaleVector(Shade, Cover);
  1048. Application.ProcessMessages;
  1049. AddVector(Shade, VectorScale(Cover, FAmbientLight));
  1050. Application.ProcessMessages;
  1051. if Shade.x > 1 then
  1052. Shade.x := 1;
  1053. if Shade.y > 1 then
  1054. Shade.y := 1;
  1055. if Shade.z > 1 then
  1056. Shade.z := 1;
  1057. // if x=Side-1 then begin Shade[0]:=1; Shade[1]:=0; Shade[2]:=0; end;
  1058. MakeRGBTriple(Shade, Result);
  1059. end;
  1060. begin
  1061. nbTiles := FSize div FTerrainRenderer.TileSize;
  1062. SetLength(Bmp, nbTiles, nbTiles);
  1063. Side := FTerrainRenderer.TileSize * TextureScale;
  1064. FTask := 'Texture creation';
  1065. FTaskProgress := 0;
  1066. // Draw bitmap
  1067. try
  1068. for yy := 0 to (nbTiles) - 1 do
  1069. begin
  1070. FTaskProgress := Round(yy / nbTiles * 100);
  1071. Application.ProcessMessages;
  1072. y0 := yy * Side;
  1073. for xx := 0 to (nbTiles) - 1 do
  1074. begin
  1075. x0 := xx * Side;
  1076. Bmp[xx, yy] := tBitmap.Create;
  1077. with Bmp[xx, yy] do
  1078. begin
  1079. PixelFormat := pf24bit;
  1080. Width := Side;
  1081. Height := Side;
  1082. for y := 0 to Side - 1 do
  1083. begin
  1084. Line := ScanLine[y];
  1085. for x := 0 to Side - 1 do
  1086. begin
  1087. Line[x] := ComputePixel(x, y);
  1088. end; // for x
  1089. end; // for y
  1090. end; // with
  1091. end; // for xx
  1092. end; // for yy
  1093. // Smoothes tile seams
  1094. for yy := 0 to nbTiles - 2 do
  1095. begin
  1096. for xx := 0 to nbTiles - 2 do
  1097. begin
  1098. for x := 0 to Side - 1 do
  1099. begin
  1100. meancol := MeanColor(Bmp[xx, yy].Canvas.Pixels[Side - 1, x], Bmp[xx + 1, yy].Canvas.Pixels[0, x]);
  1101. Bmp[xx, yy].Canvas.Pixels[Side - 1, x] := meancol;
  1102. Bmp[xx + 1, yy].Canvas.Pixels[0, x] := meancol;
  1103. meancol := MeanColor(Bmp[xx, yy].Canvas.Pixels[x, Side - 1], Bmp[xx, yy + 1].Canvas.Pixels[x, 0]);
  1104. Bmp[xx, yy].Canvas.Pixels[x, Side - 1] := meancol;
  1105. Bmp[xx, yy + 1].Canvas.Pixels[x, 0] := meancol;
  1106. end; // for x
  1107. end; // for xx
  1108. end; // for yy
  1109. // Upload into material library
  1110. for yy := 0 to nbTiles - 1 do
  1111. begin
  1112. for xx := 0 to nbTiles - 1 do
  1113. begin
  1114. with FTerrainRenderer.MaterialLibrary.AddTextureMaterial(Format('%s%d%d', [Self.Name, xx, yy]), Bmp[xx, yy]) do
  1115. begin
  1116. // Material.Texture.MinFilter:=miNearest;
  1117. Material.Texture.TextureWrap := twNone;
  1118. Material.MaterialOptions := [moNoLighting];
  1119. // Needed for correct look when lighting is enabled
  1120. end; // with
  1121. // Bmp[xx,yy].SaveToFile(Format('%s%d%d.bmp',[Self.Name,xx,yy]));
  1122. end; // for xx
  1123. end; // for yy
  1124. finally
  1125. for yy := 0 to nbTiles - 2 do
  1126. begin
  1127. for xx := 0 to nbTiles - 2 do
  1128. begin
  1129. Bmp[xx, yy].Free;
  1130. end; // for xx
  1131. end; // for yy
  1132. Bmp := nil;
  1133. end; // finally
  1134. end; // *)
  1135. (* procedure TGLCustomRandomHDS.BuildTexture2;
  1136. var
  1137. Bmp :tBitmap;
  1138. Mat :TGLLibMaterial;
  1139. x,y :integer;
  1140. i,j :integer;
  1141. Shade :tColorVector;
  1142. Cover :tColorVector;
  1143. z :double;
  1144. begin
  1145. if not fTextureCreated then CreateTexture;
  1146. Mat:=FTerrainRenderer.MaterialLibrary.LibMaterialByName(MaterialName);
  1147. Bmp:=TBitmap.Create;
  1148. fTask:='Texture creation';
  1149. fTaskProgress:=0;
  1150. {Draw bitmap}
  1151. try
  1152. with Bmp do begin
  1153. PixelFormat:=pf24bit;
  1154. Width:=fSize*TextureScale;
  1155. Height:=fSize*TextureScale;
  1156. with Canvas do begin
  1157. for y:=0 to fSize*TextureScale-1 do begin
  1158. fTaskProgress:=Round(y/(fSize*TextureScale)*100);
  1159. Application.ProcessMessages;
  1160. for x:=0 to fSize*TextureScale-1 do begin
  1161. i:=x div TextureScale;
  1162. j:=y div TextureScale;
  1163. z:=Interpolate(x/TextureScale,y/TextureScale);
  1164. Cover:=OnDrawTexture(Self,x,y,z,fNormal[i,j]);
  1165. Shade:=VectorScale(fLightColor.Color,fLightMap[x,y]);
  1166. ScaleVector(Shade,Cover);
  1167. AddVector(Shade,VectorScale(Cover,fAmbientLight));
  1168. if Shade[0]>1 then Shade[0]:=1;
  1169. if Shade[1]>1 then Shade[1]:=1;
  1170. if Shade[2]>1 then Shade[2]:=1;
  1171. Pixels[x,y]:=ConvertColorVector(Shade);
  1172. end;//for x
  1173. end;//for y
  1174. end;//with
  1175. end;//with
  1176. //Bmp.SaveToFile('test.bmp');
  1177. {Use it as texture}
  1178. with Mat.Material.Texture do begin
  1179. Image.Assign(Bmp);
  1180. Image.NotifyChange(Self);
  1181. Enabled:=true;
  1182. //MagFilter:=maNearest;
  1183. //MinFilter:=miNearest;
  1184. end;//with }
  1185. Mat.NotifyUsersOfTexMapChange;
  1186. finally
  1187. Bmp.Free;
  1188. end;//finally
  1189. end;// *)
  1190. procedure TGLCustomRandomHDS.ClearHeightField;
  1191. begin
  1192. PrimerNull(FHeight);
  1193. end;
  1194. procedure TGLCustomRandomHDS.ClearLightMap;
  1195. var
  1196. x, y: integer;
  1197. begin
  1198. SetLength(FLightMap, (FSize + 1) * TextureScale, (FSize + 1) * TextureScale);
  1199. for y := 0 to High(FLightMap) do
  1200. begin
  1201. for x := 0 to High(FLightMap) do
  1202. begin
  1203. FLightMap[x, y] := 1;
  1204. end; // for
  1205. end; // for
  1206. end;
  1207. procedure TGLCustomRandomHDS.ConstrainCoordinates(var x, y: integer);
  1208. begin
  1209. FIntegerConstrain(x, y);
  1210. end;
  1211. procedure TGLCustomRandomHDS.ConstrainCoordinates(var x, y: single);
  1212. begin
  1213. FSingleConstrain(x, y);
  1214. end;
  1215. constructor TGLCustomRandomHDS.Create(AOwner: TComponent);
  1216. begin
  1217. inherited;
  1218. FLandCover := True;
  1219. FOnDrawTexture := OnDrawTextureDefault;
  1220. end;
  1221. procedure TGLCustomRandomHDS.CyclicClamp(var x, y: single);
  1222. var
  1223. ix, iy: integer;
  1224. sx, sy: single;
  1225. begin
  1226. ix := Trunc(x);
  1227. sx := Frac(x);
  1228. iy := Trunc(y);
  1229. sy := Frac(y);
  1230. x := (FSize + ix) mod FSize + sx;
  1231. y := (FSize + iy) mod FSize + sy;
  1232. end;
  1233. procedure TGLCustomRandomHDS.CyclicClamp(var x, y: integer);
  1234. begin
  1235. x := (FSize + x) mod FSize;
  1236. y := (FSize + y) mod FSize;
  1237. end;
  1238. destructor TGLCustomRandomHDS.Destroy;
  1239. var
  1240. x, y: integer;
  1241. Mat: TGLLibMaterial;
  1242. begin
  1243. FLandTileInfo.State := hdsNone;
  1244. FHeight := nil;
  1245. FLightMap := nil;
  1246. FNormal := nil;
  1247. try
  1248. for y := 0 to (FSize div FTerrainRenderer.TileSize) - 1 do
  1249. begin
  1250. for x := 0 to (FSize div FTerrainRenderer.TileSize) - 1 do
  1251. begin
  1252. Mat := FTerrainRenderer.MaterialLibrary.LibMaterialByName(Format('%s%d%d', [Self.Name, x, y]));
  1253. if Mat <> nil then
  1254. Mat.Material.DestroyHandles;
  1255. end; // for x
  1256. end; // for y
  1257. except
  1258. end;
  1259. if (FSlave) and (Owner <> nil) then
  1260. with LandTileInfo do
  1261. TGLTiledRndLandscape(Owner).MarkDirty(x * FSize, z * FSize, (x + 1) * FSize - 1, (z + 1) * FSize - 1);
  1262. inherited;
  1263. end;
  1264. procedure TGLCustomRandomHDS.DoCyclicBoundaries;
  1265. var
  1266. i: integer;
  1267. begin
  1268. for i := 0 to FSize do
  1269. begin
  1270. FHeight[i, FSize] := FHeight[i, 0];
  1271. FHeight[FSize, i] := FHeight[0, i];
  1272. end; // for
  1273. end;
  1274. procedure TGLCustomRandomHDS.DoErosionByFraction;
  1275. begin
  1276. end;
  1277. procedure TGLCustomRandomHDS.DoErosionByLife;
  1278. var
  1279. x, y, i: integer;
  1280. z, z1: single;
  1281. begin
  1282. { Smoothing by a 3-by-3 mean filter }
  1283. FTask := 'Erosion by life';
  1284. FTaskProgress := 0;
  1285. for y := 0 to FSize do
  1286. begin
  1287. FTaskProgress := Round(y / (FSize) * 100);
  1288. for x := 0 to FSize do
  1289. begin
  1290. Application.ProcessMessages;
  1291. z := FHeight[x, y] * FErosionByLife.Robustness;
  1292. z1 := FErosionByLife.Robustness;
  1293. for i := 0 to 7 do
  1294. begin
  1295. z := z + Heights[x + NeighX[i], y + NeighY[i]] * NeighW[i];
  1296. z1 := z1 + NeighW[i];
  1297. end; // for i
  1298. FHeight[x, y] := z / z1;
  1299. end; // for x
  1300. end; // for y
  1301. end;
  1302. procedure TGLCustomRandomHDS.DoErosionByRain;
  1303. { Drop some rain on every cell of the landscape and let it run downward, taking soil
  1304. on its way. When it arrives into a pool, let it deposit all that has been eroded. }
  1305. const
  1306. Ks = 0.001; // Soil solubility
  1307. var
  1308. j: integer;
  1309. x0, y0: integer;
  1310. x, y: integer;
  1311. x1, y1: integer;
  1312. minx, miny: integer;
  1313. z, z1: single;
  1314. MinZ: single;
  1315. dz, mindz: single;
  1316. Charge: double;
  1317. From, Next: integer;
  1318. begin
  1319. FTask := 'Rain erosion simulation';
  1320. FTaskProgress := 0;
  1321. minx := 0;
  1322. miny := 0;
  1323. MinZ := 0;
  1324. Next := 0;
  1325. { Rain }
  1326. for y0 := 0 to FSize do
  1327. begin
  1328. FTaskProgress := Round(y0 / (FSize) * 100);
  1329. for x0 := 0 to FSize do
  1330. begin
  1331. Application.ProcessMessages;
  1332. x := x0;
  1333. y := y0;
  1334. z := StandardisedHeight(x, y);
  1335. Charge := 0;
  1336. From := -1;
  1337. while (FHeight[x, y] > FSeaLevel) // Not in the sea
  1338. do
  1339. begin
  1340. mindz := MaxInt;
  1341. for j := 0 to 7 do
  1342. begin // Look for the largest slope
  1343. if j = From then
  1344. continue; // Never go backward
  1345. x1 := (FSize + x + NeighX[j]) mod FSize; // Cyclic landscape
  1346. y1 := (FSize + y + NeighY[j]) mod FSize;
  1347. z1 := StandardisedHeight(x1, y1);
  1348. dz := (z1 - z) * NeighW[j];
  1349. if dz < mindz then
  1350. begin
  1351. minx := x1;
  1352. miny := y1;
  1353. MinZ := z1;
  1354. mindz := dz;
  1355. Next := j;
  1356. end; // if
  1357. end; // for j
  1358. if (StandardisedHeight(minx, miny) <= SeaLevel) then
  1359. break; // In the sea or out of map
  1360. if MinZ < z then
  1361. begin
  1362. FHeight[x, y] := FHeight[x, y] - FErosionByRain.ErosionRate * Ks * FRangeHeight; // Erosion
  1363. x := minx;
  1364. y := miny;
  1365. z := MinZ;
  1366. From := (Next + 4) mod 8; // Opposite direction
  1367. Charge := Charge + 1;
  1368. end // if
  1369. else
  1370. begin // Fallen into a pool? Deposit the charge
  1371. FHeight[x, y] := FHeight[x, y] + MinFloat(MinZ - z, FErosionByRain.DepositRate * Ks * FRangeHeight * Charge);
  1372. break; // Go to next rain drop
  1373. end; // else
  1374. end; // while
  1375. end; // for x0
  1376. end; // for y0
  1377. end; // *)
  1378. (*
  1379. Variants:
  1380. procedure TGLBaseRandomHDS.DoErosionByRain(const Intensity: single);
  1381. const
  1382. NeighX :array[0..7] of integer=(-1, 0, 1, 1, 1, 0,-1,-1);
  1383. NeighY :array[0..7] of integer=(-1,-1,-1, 0, 1, 1, 1, 0);
  1384. NeighW :array[0..7] of single=(1/1.4142,1,1/1.4142,1,1/1.4142,1,1/1.4142,1);
  1385. type
  1386. tFlow=record
  1387. NextX,NextY :integer;
  1388. Slope :single;
  1389. Erosion :integer;
  1390. end;
  1391. var
  1392. Flow :array of array of tFlow;
  1393. i,j,jj,swap :integer;
  1394. x0,y0 :integer;
  1395. x,y :integer;
  1396. x1,y1 :integer;
  1397. minx,miny :integer;
  1398. z,z1,minz :single;
  1399. Charge :integer;
  1400. N :integer;
  1401. From,Next :integer;
  1402. Sig :integer;
  1403. c :double;
  1404. OldSlope :single;
  1405. dz,mindz :single;
  1406. begin
  1407. c:=1/VSF/sqrt(sqr(Scale.X)+sqr(Scale.Z));
  1408. {Water flow map computation}
  1409. SetLength(Flow,fSize+1,fSize+1);
  1410. for y:=0 to fSize do begin
  1411. for x:=0 to fSize do begin
  1412. mindz:=MaxInt;
  1413. Sig:=Sign(random*2-1);
  1414. z:=fHeight[x,y];
  1415. for jj:=0 to 7 do begin // Look for the largest slope
  1416. j:=(8+Sig*jj) mod 8;
  1417. x1:=x+NeighX[j];
  1418. y1:=y+NeighY[j];
  1419. try z1:=Height[x1,y1];
  1420. dz:=(z1-z)*NeighW[j];
  1421. if dz+random*0.03*fRangeHeight<mindz then begin
  1422. minx:=x1;
  1423. miny:=y1;
  1424. minz:=z1;
  1425. mindz:=dz;
  1426. Next:=j;
  1427. end;//if
  1428. except // Out of the map? Then go to next rain drop
  1429. Flow[x,y].NextX:=-99;
  1430. Break;
  1431. end;
  1432. with Flow[x,y] do begin
  1433. Slope:=ArcTan((minz-z)*c);
  1434. if Slope>0 then NextX:=-99
  1435. else begin
  1436. NextX:=minx;
  1437. NextY:=miny;
  1438. Erosion:=0;
  1439. end;//if
  1440. end;//with
  1441. end;//for j
  1442. end;//for
  1443. end;//for
  1444. From:=0;
  1445. {Rain}
  1446. for y0:=0 to fSize do begin
  1447. for x0:=0 to fSize do begin
  1448. x:=x0;
  1449. y:=y0;
  1450. OldSlope:=0;
  1451. while (x<>-99)and(fCover[x,y]>0) do begin // Not in the sea
  1452. with Flow[x,y] do begin
  1453. if (Slope*2<OldSlope) then begin
  1454. Dec(Erosion);
  1455. x:=NextX;
  1456. y:=NextY;
  1457. OldSlope:=Slope;
  1458. end//if
  1459. else begin
  1460. //Inc(Erosion);
  1461. Break;
  1462. end;//else
  1463. end;//with
  1464. end;//while
  1465. end;//for x0
  1466. end;//for y0
  1467. {Apply erosion}
  1468. for y:=0 to fSize do begin
  1469. for x:=0 to fSize do begin
  1470. //fHeight[x,y]:=fHeight[x,y]+Flow[x,y].Erosion*0.002*Intensity*fRangeHeight;
  1471. fHeight[x,y]:=(Flow[x,y].Erosion)*100+50;
  1472. end;//for
  1473. end;//for
  1474. Flow:=nil;
  1475. end; // *)
  1476. (* procedure TGLBaseRandomHDS.DoErosionByRain(const Intensity: single);
  1477. const
  1478. NeighX:array[0..7] of integer=(-1, 0, 1, 1, 1, 0,-1,-1);
  1479. NeighY:array[0..7] of integer=(-1,-1,-1, 0, 1, 1, 1, 0);
  1480. var
  1481. Erosion :array of array of single;
  1482. Flow :array[0..7] of single;
  1483. FlowSum :single;
  1484. j :integer;
  1485. x,y :integer;
  1486. x1,y1 :integer;
  1487. z,z1 :single;
  1488. c :single;
  1489. begin
  1490. c:=1/VSF; // Vertical scale factor
  1491. SetLength(Erosion,fSize+2,fSize+2);
  1492. for y:=0 to fSize+1 do for x:=0 to fSize+1 do Erosion[x,y]:=0;
  1493. {Erosion computation}
  1494. for y:=0 to fSize+1 do begin
  1495. for x:=0 to fSize+1 do begin
  1496. z:=fHeight[x,y];
  1497. FlowSum:=0;
  1498. for j:=0 to 7 do begin // Flow to adjacent cells
  1499. x1:=x+NeighX[j];
  1500. y1:=y+NeighY[j];
  1501. try
  1502. z1:=Height[x1,y1]+random*0;
  1503. if z1<z then begin
  1504. Flow[j]:=ArcTan((z-z1)*c);
  1505. FlowSum:=FlowSum+Flow[j];
  1506. end//if
  1507. else Flow[j]:=0;
  1508. except
  1509. Flow[j]:=0;
  1510. end;//except
  1511. end;//for j
  1512. if FlowSum>0 then begin // Erosion and deposition
  1513. Erosion[x,y]:=Erosion[x,y]-1; // Erosion
  1514. for j:=0 to 7 do begin
  1515. if Flow[j]>1e-3 then begin
  1516. x1:=x+NeighX[j];
  1517. y1:=y+NeighY[j];
  1518. Erosion[x1,y1]:=Erosion[x1,y1]+Flow[j]/FlowSum; // Partial deposition
  1519. end;//if
  1520. end;//for
  1521. end;//if
  1522. end;//for x
  1523. end;//for y
  1524. {Apply erosion to each cell}
  1525. for y:=0 to fSize do begin
  1526. for x:=0 to fSize do begin
  1527. fHeight[x,y]:=fHeight[x,y]+Erosion[x,y]*0.005*Intensity*fRangeHeight;
  1528. //fHeight[x,y]:=(Erosion[x,y])*100+50;
  1529. end;//for
  1530. end;//for
  1531. Erosion:=nil;
  1532. end; // *)
  1533. (* procedure TGLBaseRandomHDS.DoErosionByRain(const Intensity: single);
  1534. const
  1535. NeighX:array[0..7] of integer=(-1, 0, 1, 1, 1, 0,-1,-1);
  1536. NeighY:array[0..7] of integer=(-1,-1,-1, 0, 1, 1, 1, 0);
  1537. var
  1538. Erosion :array of array of single;
  1539. i,j,jj :integer;
  1540. x,y :integer;
  1541. x1,y1 :integer;
  1542. x2,y2 :integer;
  1543. z,z1,z2,dz :single;
  1544. begin
  1545. SetLength(Erosion,fSize+2,fSize+2);
  1546. for i:=1 to 1 do begin
  1547. //for y:=0 to fSize+1 do for x:=0 to fSize+1 do Erosion[x,y]:=0;
  1548. {Erosion computation}
  1549. for y:=5 to fSize-4 do begin
  1550. for x:=5 to fSize-4 do begin
  1551. z:=fHeight[x,y];
  1552. dz:=1;
  1553. for jj:=1 to 2 do begin // Flow to adjacent cells
  1554. j:=jj*2;
  1555. x1:=x+NeighX[j]*5;
  1556. y1:=y+NeighY[j]*5;
  1557. x2:=x+NeighX[j+4]*5;
  1558. y2:=y+NeighY[j+4]*5;
  1559. try
  1560. z1:=Height[x1,y1]+random*0;
  1561. z2:=Height[x2,y2]+random*0;
  1562. dz:=dz*Sign(z-(z1+z2)/2);
  1563. except
  1564. end;//except
  1565. end;//for j
  1566. Erosion[x,y]:=dz;
  1567. end;//for x
  1568. end;//for y
  1569. {Apply erosion to each cell}
  1570. for y:=0 to fSize do begin
  1571. for x:=0 to fSize do begin
  1572. fHeight[x,y]:=fHeight[x,y]+Erosion[x,y]*100*Intensity;
  1573. //fHeight[x,y]:=(Erosion[x,y])*1+50;
  1574. end;//for
  1575. end;//for
  1576. end;//for i
  1577. Erosion:=nil;
  1578. end; // *)
  1579. procedure TGLCustomRandomHDS.DoErosionBySea;
  1580. var
  1581. i, j: integer;
  1582. begin
  1583. for i := 0 to FSize do
  1584. begin
  1585. for j := 0 to FSize do
  1586. begin
  1587. Application.ProcessMessages;
  1588. if abs(FHeight[i, j] - FSeaLevel) < FErosionBySea.BeachHeight * VSF then
  1589. begin
  1590. FHeight[i, j] := FSeaLevel + (FHeight[i, j] - FSeaLevel) * 0.3;
  1591. end; // if
  1592. end; // for
  1593. end; // for
  1594. end;
  1595. procedure TGLCustomRandomHDS.DoSea;
  1596. var
  1597. i, j: integer;
  1598. begin
  1599. for i := 0 to FSize do
  1600. begin
  1601. for j := 0 to FSize do
  1602. begin
  1603. // if fHeight[i,j]<Lvl then fHeight[i,j]:=Lvl-random*wave;
  1604. if FHeight[i, j] < FSeaLevel - FSeaTransparency then
  1605. FHeight[i, j] := FSeaLevel - 1 // Lvl-c-random*wave
  1606. else if FHeight[i, j] < FSeaLevel then
  1607. FHeight[i, j] := FSeaLevel - (FSeaLevel - FHeight[i, j]) / FSeaTransparency;
  1608. end; // for
  1609. end; // for
  1610. end;
  1611. procedure TGLCustomRandomHDS.DoSteps;
  1612. var
  1613. i, j: integer;
  1614. Stp: single;
  1615. begin
  1616. Stp := (FMaxHeight - FSeaLevel) / FSteps.Count; // Step height
  1617. for i := 0 to FSize do
  1618. begin
  1619. for j := 0 to FSize do
  1620. begin
  1621. FHeight[i, j] := Round(FHeight[i, j] / Stp) * Stp;
  1622. end; // for
  1623. end; // for
  1624. end;
  1625. function TGLCustomRandomHDS.GetHeight(x, y: integer): single;
  1626. begin
  1627. FIntegerConstrain(x, y);
  1628. Result := FHeight[x, y];
  1629. end;
  1630. procedure TGLCustomRandomHDS.GetTerrainBounds(var l, t, r, b: single);
  1631. begin
  1632. l := 0;
  1633. b := 0;
  1634. t := FSize;
  1635. r := FSize;
  1636. end;
  1637. // Copied from GLHeightData.InterpolatedHeight
  1638. function TGLCustomRandomHDS.Interpolate(x, y: single): single;
  1639. var
  1640. ix, iy: integer;
  1641. h1, h2, h3: single;
  1642. begin
  1643. ix := Trunc(x);
  1644. x := Frac(x);
  1645. iy := Trunc(y);
  1646. y := Frac(y);
  1647. if x > y then
  1648. begin
  1649. // top-right triangle
  1650. h1 := Heights[ix + 1, iy];
  1651. h2 := Heights[ix, iy];
  1652. h3 := Heights[ix + 1, iy + 1];
  1653. Result := h1 + (h2 - h1) * (1 - x) + (h3 - h1) * y;
  1654. end
  1655. else
  1656. begin
  1657. // bottom-left triangle
  1658. h1 := Heights[ix, iy + 1];
  1659. h2 := Heights[ix + 1, iy + 1];
  1660. h3 := Heights[ix, iy];
  1661. Result := h1 + (h2 - h1) * (x) + (h3 - h1) * (1 - y);
  1662. end;
  1663. end;
  1664. function TGLCustomRandomHDS.PointInMap(const x, y: single): boolean;
  1665. begin
  1666. Result := (x >= 0) and (x <= FSize) and (y >= 0) and (y <= FSize);
  1667. end;
  1668. function TGLCustomRandomHDS.Normal(const Position: TVector): TVector;
  1669. var
  1670. x, y: integer;
  1671. begin
  1672. if (FNormal <> nil) then
  1673. begin
  1674. Result := FTerrainRenderer.AbsoluteToLocal(Position);
  1675. x := Round(Result.x);
  1676. y := Round(Result.y);
  1677. FIntegerConstrain(x, y);
  1678. Result := FNormal[x, y];
  1679. end // if
  1680. else
  1681. raise EAccessViolation.Create('No normal array computed.');
  1682. end;
  1683. function TGLCustomRandomHDS.PointInMap(const x, y: integer): boolean;
  1684. begin
  1685. Result := (x >= 0) and (x <= FSize) and (y >= 0) and (y <= FSize);
  1686. end;
  1687. function TGLCustomRandomHDS.Scale: TGLCoordinates;
  1688. begin
  1689. try
  1690. Result := FTerrainRenderer.Scale;
  1691. except
  1692. raise EAccessViolation.Create('No TerrainRenderer defined');
  1693. end;
  1694. end;
  1695. procedure TGLCustomRandomHDS.SetCyclic(const Value: boolean);
  1696. begin
  1697. FCyclic := Value;
  1698. if FCyclic then
  1699. begin
  1700. FIntegerConstrain := CyclicClamp;
  1701. FSingleConstrain := CyclicClamp;
  1702. if FTerrainRenderer <> nil then
  1703. FTerrainRenderer.OnGetTerrainBounds := nil;
  1704. end
  1705. else
  1706. begin
  1707. FIntegerConstrain := BoundaryClamp;
  1708. FSingleConstrain := BoundaryClamp;
  1709. if FTerrainRenderer <> nil then
  1710. FTerrainRenderer.OnGetTerrainBounds := GetTerrainBounds;
  1711. end; // else
  1712. end;
  1713. procedure TGLCustomRandomHDS.SetHeight(x, y: integer; const Value: single);
  1714. begin
  1715. FIntegerConstrain(x, y);
  1716. FHeight[x, y] := Value;
  1717. end;
  1718. procedure TGLCustomRandomHDS.SetSize(const aSize: integer);
  1719. var
  1720. Tile: integer;
  1721. begin
  1722. FSize := aSize;
  1723. if FSize > 32 then
  1724. Tile := 32
  1725. else
  1726. Tile := Round(IntPower(2, Trunc(ln(FSize - 1) / ln(2))));
  1727. SetLength(FHeight, FSize + 1, FSize + 1);
  1728. SetLength(FNormal, FSize + 1, FSize + 1);
  1729. MaxPoolSize := sqr(FSize) * SizeOf(smallint);
  1730. if FTerrainRenderer <> nil then
  1731. begin
  1732. FTerrainRenderer.TileSize := Tile;
  1733. FTerrainRenderer.TilesPerTexture := FSize div FTerrainRenderer.TileSize;
  1734. end; // if
  1735. end;
  1736. procedure TGLCustomRandomHDS.SetTerrainRenderer(const Value: TGLTerrainRenderer);
  1737. begin
  1738. FTerrainRenderer := Value;
  1739. if not FSlave then
  1740. begin
  1741. FTerrainRenderer.OnGetTerrainBounds := GetTerrainBounds;
  1742. FTerrainRenderer.HeightDataSource := Self;
  1743. end; // if
  1744. end;
  1745. function TGLCustomRandomHDS.StandardisedHeight(const x, y: integer): single;
  1746. begin
  1747. Result := (Heights[x, y] - FMinHeight) / FRangeHeight * 1000;
  1748. end;
  1749. procedure TGLCustomRandomHDS.StartPreparingData(heightData: TGLHeightData);
  1750. var
  1751. x, y, x0, y0: integer;
  1752. rasterLine: GLHeightData.PSmallIntArray;
  1753. oldType: TGLHeightDataType;
  1754. begin
  1755. with heightData do
  1756. begin
  1757. DataState := hdsPreparing;
  1758. oldType := DataType;
  1759. Allocate(hdtSmallInt);
  1760. if XLeft >= 0 then
  1761. x0 := XLeft mod (FSize)
  1762. else
  1763. x0 := (FSize + (XLeft mod (FSize))) mod (FSize);
  1764. if YTop >= 0 then
  1765. y0 := YTop mod (FSize)
  1766. else
  1767. y0 := (FSize + (YTop mod (FSize))) mod (FSize);
  1768. if FLandCover then
  1769. begin
  1770. MaterialName := Format('%s%d%d', [Self.Name, x0 div (heightData.Size - 1), y0 div (heightData.Size - 1)]);
  1771. TextureCoordinatesMode := tcmLocal;
  1772. TextureCoordinatesScale := TexPointMake((Self.FSize) / (heightData.Size - 1), (Self.FSize) / (heightData.Size - 1));
  1773. end // if
  1774. else
  1775. begin
  1776. MaterialName := Self.FMaterialName;
  1777. TextureCoordinatesMode := tcmLocal;
  1778. TextureCoordinatesScale := TexPointMake(FTextureScale, FTextureScale);
  1779. end; // else
  1780. for y := y0 to y0 + heightData.Size - 1 do
  1781. begin
  1782. rasterLine := smallintRaster[y - y0];
  1783. for x := x0 to x0 + heightData.Size - 1 do
  1784. begin
  1785. rasterLine[x - x0] := Round(FHeight[x, y]);
  1786. end; // for
  1787. end; // for
  1788. HeightMin := MinHeight;
  1789. HeightMax := MaxHeight;
  1790. DataState := hdsReady;
  1791. if oldType <> hdtSmallInt then
  1792. DataType := oldType;
  1793. end; // with
  1794. // inherited;
  1795. end; // *)
  1796. function TGLCustomRandomHDS.XMoveBoundary: single;
  1797. begin
  1798. Result := FSize * Scale.x * 0.95;
  1799. end;
  1800. function TGLCustomRandomHDS.ZMoveBoundary: single;
  1801. begin
  1802. Result := FSize * Scale.y * 0.95;
  1803. end;
  1804. procedure TGLCustomRandomHDS.SetKeepNormals(const Value: boolean);
  1805. begin
  1806. FKeepNormals := Value;
  1807. end;
  1808. { TGLFractalHDS }
  1809. procedure TGLFractalHDS.BuildHeightField(const aDepth, aSeed, aAmplitude: integer);
  1810. begin
  1811. fDepth := aDepth;
  1812. FSeed := aSeed;
  1813. fAmplitude := aAmplitude;
  1814. BuildHeightField;
  1815. end;
  1816. procedure TGLFractalHDS.BuildHeightField;
  1817. begin
  1818. FractalMiddlePointHDS(fDepth, FSeed, fAmplitude, fRoughness, FCyclic, FHeight, FMinHeight, FMaxHeight);
  1819. FRangeHeight := FMaxHeight - FMinHeight;
  1820. Scale.x := 1;
  1821. Scale.y := 1;
  1822. Scale.z := FSize / VSF;
  1823. end;
  1824. constructor TGLFractalHDS.Create(AOwner: TComponent);
  1825. begin
  1826. inherited;
  1827. Depth := 4;
  1828. FSea := True;
  1829. Amplitude := 50;
  1830. fRoughness := 0.4;
  1831. end;
  1832. procedure TGLFractalHDS.SetAmplitude(const Value: integer);
  1833. begin
  1834. fAmplitude := Value;
  1835. FMinHeight := -fAmplitude / 2 * VSF;
  1836. FMaxHeight := -FMinHeight;
  1837. FRangeHeight := fAmplitude * VSF;
  1838. end;
  1839. procedure TGLFractalHDS.SetDepth(const Value: integer);
  1840. begin
  1841. fDepth := Value;
  1842. SetSize(Round(IntPower(2, fDepth)));
  1843. end;
  1844. procedure TGLFractalHDS.SetRoughness(const Value: single);
  1845. begin
  1846. fRoughness := Value;
  1847. end;
  1848. //-----------------------------------
  1849. // TGLRandomLandscape
  1850. //-----------------------------------
  1851. procedure TGLTiledRndLandscape.ApplyLighting(var aLandTile: TGLLandTile);
  1852. begin
  1853. with aLandTile do
  1854. begin
  1855. Lighting := Self.FLighting;
  1856. LightColor := Self.FLightColor;
  1857. LightDirection := Self.FLightDirection;
  1858. LightSmoothing := Self.FLightSmoothing;
  1859. Shadows := Self.Shadows;
  1860. end; // with
  1861. end;
  1862. procedure TGLTiledRndLandscape.ApplyTexture(var aLandTile: TGLLandTile);
  1863. begin
  1864. with aLandTile do
  1865. begin
  1866. LandCover := Self.LandCover;
  1867. MaterialName := Self.FMaterialName;
  1868. TextureScale := Self.FTextureScale;
  1869. if Assigned(Self.OnDrawTexture) then
  1870. FOnDrawTexture := Self.OnDrawTexture;
  1871. end; // with
  1872. end;
  1873. procedure TGLTiledRndLandscape.ApplyTopography(var aLandTile: TGLLandTile);
  1874. begin
  1875. with aLandTile do
  1876. begin
  1877. ErosionByFraction := Self.FErosionByFraction;
  1878. ErosionByLife := Self.FErosionByLife;
  1879. ErosionByRain := Self.FErosionByRain;
  1880. ErosionBySea := Self.FErosionBySea;
  1881. FSea := Self.FSea;
  1882. FSeaLevel := Self.FSeaLevel;
  1883. FSeaTransparency := Self.FSeaTransparency;
  1884. end; // with
  1885. end;
  1886. procedure TGLTiledRndLandscape.BoundaryClamp(var x, z: single);
  1887. begin
  1888. ClampValue(x, 0, FExtentX * fLandTileSize);
  1889. ClampValue(z, 0, FExtentZ * fLandTileSize);
  1890. end;
  1891. procedure TGLTiledRndLandscape.BoundaryClamp(var x, z: integer);
  1892. begin
  1893. if x < 0 then
  1894. x := 0
  1895. else if x > FExtentX * fLandTileSize then
  1896. x := FExtentX * fLandTileSize;
  1897. if z < 0 then
  1898. z := 0
  1899. else if z > ExtentZ * fLandTileSize then
  1900. z := FExtentZ * fLandTileSize;
  1901. end;
  1902. procedure TGLTiledRndLandscape.CameraPosition(var TileX, TileZ: integer);
  1903. begin
  1904. FindLandTile(-Camera.Position.x, Camera.Position.z, TileX, TileZ);
  1905. end;
  1906. procedure TGLTiledRndLandscape.CleanUp;
  1907. var
  1908. i: integer;
  1909. begin
  1910. for i := fLandTiles.Count - 1 downto 0 do
  1911. begin
  1912. if TGLLandTile(fLandTiles.Items[i]).LandTileInfo.State = hdsNone then
  1913. begin
  1914. fLandTiles.Delete(i); // Free the Landtile and remove it from the list
  1915. // FTerrainRenderer.MaterialLibrary.Materials.DeleteUnusedMaterials;
  1916. end; // if
  1917. end; // for
  1918. end;
  1919. procedure TGLTiledRndLandscape.ComputeLandTile(const aX, aZ: integer; var NewLandTile: TGLLandTile);
  1920. var
  1921. sx, sz: string;
  1922. begin
  1923. FLandTileComputing := True;
  1924. FLandTileInfo.x := aX;
  1925. FLandTileInfo.z := aZ;
  1926. FLandTileInfo.State := hdsPreparing;
  1927. with NewLandTile do
  1928. begin
  1929. Cyclic := False;
  1930. TerrainRenderer := Self.FTerrainRenderer;
  1931. if aX >= 0 then
  1932. sx := 'p'
  1933. else
  1934. sx := 'n';
  1935. if aZ >= 0 then
  1936. sz := 'p'
  1937. else
  1938. sz := 'n';
  1939. Seed := LandTileSeed(aX, aZ);
  1940. Name := Format('Land_%s%d%s%d_', [sx, abs(aX), sz, abs(aZ)]);
  1941. // Generate a unique name
  1942. end; // with
  1943. fComputedLandTile := NewLandTile;
  1944. OnCreateLandTile(aX, aZ, NewLandTile.Seed, NewLandTile);
  1945. with NewLandTile.LandTileInfo do
  1946. FLandTileInfo.State := hdsReady;
  1947. MarkDirty(aX * fLandTileSize, aZ * fLandTileSize, (aX + 1) * fLandTileSize - 1, (aZ + 1) * fLandTileSize - 1);
  1948. fComputedLandTile := nil;
  1949. FLandTileComputing := False;
  1950. fLandTiles.Add(NewLandTile);
  1951. Application.ProcessMessages;
  1952. end;
  1953. procedure TGLTiledRndLandscape.ConstrainCoordinates(var x, z: single);
  1954. begin
  1955. FSingleConstrain(x, z);
  1956. end;
  1957. procedure TGLTiledRndLandscape.ConstrainCoordinates(var x, z: integer);
  1958. begin
  1959. FIntegerConstrain(x, z);
  1960. end;
  1961. constructor TGLTiledRndLandscape.Create(AOwner: TComponent);
  1962. begin
  1963. inherited;
  1964. fLandTiles := tComponentList.Create;
  1965. IsDefaultTile := fDefaultIsDefaultTile;
  1966. OnCreateDefaultTile := fDefaultOnCreateDefaultTile;
  1967. FExtentX := 10000;
  1968. FExtentZ := 10000;
  1969. GenerationRadius := 2;
  1970. FLandTileDensity := 1;
  1971. FLandCover := True;
  1972. end;
  1973. procedure TGLTiledRndLandscape.CyclicClamp(var x, z: integer);
  1974. begin
  1975. exit;
  1976. x := (x + ExtentX) mod ExtentX;
  1977. z := (z + ExtentZ) mod ExtentZ;
  1978. end;
  1979. procedure TGLTiledRndLandscape.CyclicClamp(var x, z: single);
  1980. var
  1981. ix, iz: integer;
  1982. sx, sz: single;
  1983. begin
  1984. exit;
  1985. ix := Trunc(ExtentX + x);
  1986. sx := Frac(x);
  1987. iz := Trunc(ExtentZ + z);
  1988. sz := Frac(z);
  1989. x := (ExtentX * fLandTileSize + ix) mod ExtentX * fLandTileSize + sx;
  1990. z := (ExtentZ * fLandTileSize + iz) mod ExtentZ * fLandTileSize + sz;
  1991. end;
  1992. destructor TGLTiledRndLandscape.Destroy;
  1993. begin
  1994. fLandTiles.Free;
  1995. inherited;
  1996. end;
  1997. function TGLTiledRndLandscape.fDefaultIsDefaultTile(x, z: integer): boolean;
  1998. begin
  1999. InitializeRandomGenerator(LandTileSeed(x, z));
  2000. Result := (random >= FLandTileDensity);
  2001. end;
  2002. procedure TGLTiledRndLandscape.fDefaultOnCreateDefaultTile(heightData: TGLHeightData);
  2003. begin
  2004. heightData.DataState := hdsNone;
  2005. // raise EAccessViolation.Create('No DefaultStartPreparingDefaultTile procedure supplied.');
  2006. end;
  2007. procedure TGLTiledRndLandscape.FindLandTile(const x, z: single; var TileX, TileZ: integer);
  2008. begin
  2009. TileX := Floor(x / fLandTileSize);
  2010. TileZ := Floor(z / fLandTileSize);
  2011. FIntegerConstrain(TileX, TileZ);
  2012. end;
  2013. function TGLTiledRndLandscape.fSortLandscapes(Item1, Item2: Pointer): integer;
  2014. { Sort landtiles from the closest to the farthest }
  2015. var
  2016. x, z: integer;
  2017. d1, d2: single;
  2018. begin
  2019. CameraPosition(x, z);
  2020. d1 := sqr(x - TGLLandTile(Item1^).LandTileInfo.x) + sqr(z - TGLLandTile(Item1^).LandTileInfo.z);
  2021. d2 := sqr(x - TGLLandTile(Item2^).LandTileInfo.x) + sqr(z - TGLLandTile(Item2^).LandTileInfo.z);
  2022. Result := Round(d1 - d2);
  2023. end;
  2024. function TGLTiledRndLandscape.GetTask: string;
  2025. begin
  2026. if fComputedLandTile <> nil then
  2027. Result := fComputedLandTile.Task
  2028. else
  2029. Result := 'Idle';
  2030. end;
  2031. function TGLTiledRndLandscape.GetTaskProgress: integer;
  2032. begin
  2033. if fComputedLandTile <> nil then
  2034. Result := fComputedLandTile.TaskProgress
  2035. else
  2036. Result := 0;
  2037. end;
  2038. procedure TGLTiledRndLandscape.GetTerrainBounds(var l, t, r, b: single);
  2039. begin
  2040. l := 0;
  2041. b := 0;
  2042. t := ExtentZ * LandTileSize;
  2043. r := ExtentX * LandTileSize;
  2044. end;
  2045. procedure TGLTiledRndLandscape.Initialize(const aX, aZ: single);
  2046. var
  2047. cx, cz: integer;
  2048. NewLandTile: TGLLandTile;
  2049. x, z, dx, dz: integer;
  2050. begin
  2051. fOldCamX := -99999;
  2052. fOldCamZ := -99999;
  2053. with Camera.Position do
  2054. begin
  2055. x := aX;
  2056. z := aZ;
  2057. end; // with
  2058. CameraPosition(cx, cz);
  2059. ComputeLandTile(cx, cz, NewLandTile);
  2060. TerrainRenderer.Scale := NewLandTile.Scale;
  2061. with Camera.Position do
  2062. begin
  2063. x := x * NewLandTile.Scale.x;
  2064. z := z * NewLandTile.Scale.z;
  2065. end; // with
  2066. for z := 0 to FGenerationRadius + 1 do
  2067. begin
  2068. for x := 1 to FGenerationRadius + 1 do
  2069. begin
  2070. if Trunc(sqrt(sqr(x) + sqr(z))) <= FGenerationRadius then
  2071. begin
  2072. dx := x;
  2073. dz := z;
  2074. if not IsDefaultTile(cx + dx, cz + dz) then
  2075. ComputeLandTile(cx + dx, cz + dz, NewLandTile);
  2076. dx := -z;
  2077. dz := x;
  2078. if not IsDefaultTile(cx + dx, cz + dz) then
  2079. ComputeLandTile(cx + dx, cz + dz, NewLandTile);
  2080. dx := -x;
  2081. dz := -z;
  2082. if not IsDefaultTile(cx + dx, cz + dz) then
  2083. ComputeLandTile(cx + dx, cz + dz, NewLandTile);
  2084. dx := z;
  2085. dz := -x;
  2086. if not IsDefaultTile(cx + dx, cz + dz) then
  2087. ComputeLandTile(cx + dx, cz + dz, NewLandTile);
  2088. end; // if
  2089. end; // for
  2090. end; // for
  2091. end;
  2092. // Generates a unique seed from the tile coordinates
  2093. function TGLTiledRndLandscape.LandTileSeed(x, z: integer): integer;
  2094. begin
  2095. Result := fBaseSeed + z * ExtentX + x;
  2096. end;
  2097. function TGLTiledRndLandscape.LandtileCount: integer;
  2098. begin
  2099. Result := fLandTiles.Count;
  2100. end;
  2101. (* procedure TGLTiledRndLandscape.PrepareLandTileData(HeightData: tHeightData;
  2102. LandTile: tLandTile);
  2103. var
  2104. x,y,x0,y0 :integer;
  2105. rasterLine :GLHeightData.PSingleArray;
  2106. oldType :THeightDataType;
  2107. begin
  2108. with HeightData do begin
  2109. DataState:=hdsPreparing;
  2110. oldType:=DataType;
  2111. Allocate(hdtSingle);
  2112. if XLeft>=0 then x0:=XLeft mod (fLandTileSize) else x0:=(fLandTileSize+(XLeft mod (fLandTileSize)))mod (fLandTileSize);
  2113. if YTop>=0 then y0:=YTop mod (fLandTileSize) else y0:=(fLandTileSize+(YTop mod (fLandTileSize)))mod (fLandTileSize);
  2114. MaterialName:=Format('%s%d%d',[LandTile.Name,x0 div fTerrainRenderer.TileSize,
  2115. y0 div fTerrainRenderer.TileSize]);
  2116. TextureCoordinatesMode:=tcmLocal;
  2117. TextureCoordinatesScale:=TexPointMake((fLandTileSize)/(Size),
  2118. (fLandTileSize)/(Size));
  2119. for y:=y0 to y0+heightData.Size-1 do begin
  2120. rasterLine:=singleRaster[y-y0];
  2121. for x:=x0 to x0+heightData.Size-1 do begin
  2122. rasterLine[x-x0]:=LandTile.fHeight[x,y];
  2123. end;//for
  2124. end;//for
  2125. DataState:=hdsReady;
  2126. if oldType<>hdtSingle then DataType:=oldType;
  2127. end;//with
  2128. end; *)
  2129. procedure TGLTiledRndLandscape.SetCamera(const Value: TGLCamera);
  2130. begin
  2131. FCamera := Value;
  2132. end;
  2133. procedure TGLTiledRndLandscape.SetCyclic(const Value: boolean);
  2134. begin
  2135. FCyclic := Value;
  2136. if FCyclic then
  2137. begin
  2138. FIntegerConstrain := CyclicClamp;
  2139. FSingleConstrain := CyclicClamp;
  2140. if FTerrainRenderer <> nil then
  2141. FTerrainRenderer.OnGetTerrainBounds := nil;
  2142. end
  2143. else
  2144. begin
  2145. FIntegerConstrain := BoundaryClamp;
  2146. FSingleConstrain := BoundaryClamp;
  2147. if FTerrainRenderer <> nil then
  2148. FTerrainRenderer.OnGetTerrainBounds := GetTerrainBounds;
  2149. end; // else
  2150. end;
  2151. procedure TGLTiledRndLandscape.SetExtentX(const Value: integer);
  2152. begin
  2153. FExtentX := Value;
  2154. FExtentXhalf := FExtentX div 2;
  2155. end;
  2156. procedure TGLTiledRndLandscape.SetExtentZ(const Value: integer);
  2157. begin
  2158. FExtentZ := Value;
  2159. FExtentZhalf := FExtentZ div 2;
  2160. end;
  2161. procedure TGLTiledRndLandscape.SetGenerationRadius(const Value: integer);
  2162. var
  2163. x, z, i: integer;
  2164. begin
  2165. FGenerationRadius := Value;
  2166. SetLength(fGenRadius, sqr(FGenerationRadius * 2 + 1));
  2167. i := 0;
  2168. for z := 0 to FGenerationRadius do
  2169. begin
  2170. for x := 1 to FGenerationRadius do
  2171. begin
  2172. if Trunc(sqrt(sqr(x) + sqr(z))) <= FGenerationRadius then
  2173. begin
  2174. fGenRadius[i].dx := x;
  2175. fGenRadius[i].dz := z;
  2176. fGenRadius[i + 1].dx := -z;
  2177. fGenRadius[i + 1].dz := x;
  2178. fGenRadius[i + 2].dx := -x;
  2179. fGenRadius[i + 2].dz := -z;
  2180. fGenRadius[i + 3].dx := z;
  2181. fGenRadius[i + 3].dz := -x;
  2182. Inc(i, 4);
  2183. end; // if
  2184. end; // for
  2185. end; // for
  2186. SetLength(fGenRadius, i - 3);
  2187. fLandTiles.Capacity := (i - 3) * 2;
  2188. end;
  2189. procedure TGLTiledRndLandscape.SetIsDefaultTile(const Value: TIsDefaultTile);
  2190. begin
  2191. FIsDefaultTile := Value;
  2192. end;
  2193. procedure TGLTiledRndLandscape.SetLandTileCapacity(const Value: integer);
  2194. begin
  2195. FLandTileCapacity := Value;
  2196. end;
  2197. procedure TGLTiledRndLandscape.SetLandTileDensity(const Value: single);
  2198. begin
  2199. FLandTileDensity := Value;
  2200. end;
  2201. procedure TGLTiledRndLandscape.SetOnCreateDefaultTile(const Value: TStartPreparingDataEvent);
  2202. begin
  2203. fOnCreateDefaultTile := Value;
  2204. end;
  2205. procedure TGLTiledRndLandscape.SetOnCreateLandTile(const Value: TOnCreateLandTile);
  2206. begin
  2207. fOnCreateLandTile := Value;
  2208. end;
  2209. procedure TGLTiledRndLandscape.SetSeed(const Value: integer);
  2210. begin
  2211. FSeed := Value;
  2212. InitializeRandomGenerator(FSeed);
  2213. end;
  2214. procedure TGLTiledRndLandscape.SetSize(const aSize: integer);
  2215. begin
  2216. fLandTileSize := aSize;
  2217. end;
  2218. procedure TGLTiledRndLandscape.SetTerrainRenderer(const Value: TGLTerrainRenderer);
  2219. begin
  2220. FTerrainRenderer := Value;
  2221. FTerrainRenderer.HeightDataSource := Self;
  2222. end;
  2223. procedure TGLTiledRndLandscape.StartPreparingData(heightData: TGLHeightData);
  2224. var
  2225. i: integer;
  2226. tx, tz: integer;
  2227. begin
  2228. with heightData do
  2229. begin
  2230. DataState := hdsPreparing;
  2231. if (System.abs(XLeft) mod (heightData.Size - 1) = 0) and (System.abs(YTop) mod (heightData.Size - 1) = 0) then
  2232. begin
  2233. FindLandTile(XLeft, YTop, tx, tz);
  2234. if IsDefaultTile(tx, tz) then
  2235. begin
  2236. OnCreateDefaultTile(heightData);
  2237. exit;
  2238. end; // if
  2239. { Look if the landtile has already been computed }
  2240. for i := 0 to fLandTiles.Count - 1 do
  2241. begin
  2242. with TGLLandTile(fLandTiles.Items[i]).LandTileInfo do
  2243. begin
  2244. if (x = tx) and (z = tz) then
  2245. begin
  2246. if (State = hdsReady) then
  2247. begin
  2248. TGLLandTile(fLandTiles.Items[i]).StartPreparingData(heightData);
  2249. exit;
  2250. end
  2251. else
  2252. break;
  2253. end; // if
  2254. end; // with
  2255. end; // for
  2256. end; // if
  2257. DataState := hdsNone;
  2258. end; // with
  2259. end;
  2260. function TGLTiledRndLandscape.TileDistance(const x1, z1, x2, z2: integer): single;
  2261. begin
  2262. Result := sqrt(sqr(FExtentXhalf - abs(abs(x1 - x2) - FExtentXhalf)) + sqr(FExtentZhalf - abs(abs(z1 - z2) - FExtentZhalf)));
  2263. end;
  2264. function TGLTiledRndLandscape.TileDistanceSquared(const x1, z1, x2, z2: integer): integer;
  2265. begin
  2266. Result := sqr(FExtentXhalf - abs(abs(x1 - x2) - FExtentXhalf)) + sqr(FExtentZhalf - abs(abs(z1 - z2) - FExtentZhalf));
  2267. end;
  2268. procedure TGLTiledRndLandscape.Update;
  2269. var
  2270. i, j, maxi: integer;
  2271. maxd, d: integer;
  2272. cx, cz: integer;
  2273. cx0, cz0: integer;
  2274. Found: boolean;
  2275. NewLandTile: TGLLandTile;
  2276. begin
  2277. CameraPosition(cx0, cz0);
  2278. if fMapUpdating or (fOldCamX = cx0) and (fOldCamZ = cz0) then
  2279. exit;
  2280. for j := 0 to High(fGenRadius) do
  2281. begin
  2282. fMapUpdating := True;
  2283. cx := cx0 + fGenRadius[j].dx;
  2284. cz := cz0 + fGenRadius[j].dz;
  2285. FIntegerConstrain(cx, cz);
  2286. if IsDefaultTile(cx, cz) then
  2287. continue;
  2288. { Look if the landtile has already been computed }
  2289. Found := False;
  2290. for i := 0 to fLandTiles.Count - 1 do
  2291. begin
  2292. with TGLLandTile(fLandTiles.Items[i]).LandTileInfo do
  2293. begin
  2294. if (x = cx) and (z = cz) and (State = hdsReady) then
  2295. begin
  2296. Found := True;
  2297. break;
  2298. end; // if
  2299. end; // with
  2300. end; // for
  2301. { If not, compute it }
  2302. if not Found and not FLandTileComputing then
  2303. begin
  2304. if fLandTiles.Count >= FLandTileCapacity then
  2305. begin // If the tile buffer is full...
  2306. maxd := -1; // ...replace the farthest tile
  2307. maxi := -1;
  2308. for i := 0 to fLandTiles.Count - 1 do
  2309. with TGLLandTile(fLandTiles.Items[i]) do
  2310. begin
  2311. d := sqr(cx0 - LandTileInfo.x) + sqr(cz0 - LandTileInfo.z);
  2312. if d > maxd then
  2313. begin
  2314. maxd := d;
  2315. maxi := i;
  2316. end; // if
  2317. end; // for i
  2318. if sqrt(maxd) > FGenerationRadius + 1 then
  2319. begin
  2320. TGLLandTile(fLandTiles.Items[maxi]).Free;
  2321. end; // if
  2322. end; // if
  2323. ComputeLandTile(cx, cz, NewLandTile);
  2324. fMapUpdating := False;
  2325. exit; // Don't explore further. Let it for the next time step
  2326. end; // if
  2327. end; // for j
  2328. fMapUpdating := False;
  2329. fOldCamX := cx0; // Surrounding completely updated, we can stop checking
  2330. fOldCamZ := cz0;
  2331. fLandTiles.Pack;
  2332. end;
  2333. function TGLTiledRndLandscape.XMoveBoundary: single;
  2334. begin
  2335. Result := ExtentX * LandTileSize * 0.95;
  2336. end;
  2337. function TGLTiledRndLandscape.ZMoveBoundary: single;
  2338. begin
  2339. Result := ExtentZ * LandTileSize * 0.95;
  2340. end;
  2341. //
  2342. // TGLFractalArchipelago
  2343. //
  2344. procedure TGLFractalArchipelago.ComputeLandTile(const aX, aZ: integer; var NewLandTile: TGLLandTile);
  2345. begin
  2346. NewLandTile := TGLFractalHDS.Create(Self);
  2347. NewLandTile.FSlave := True;
  2348. inherited ComputeLandTile(aX, aZ, NewLandTile);
  2349. end;
  2350. constructor TGLFractalArchipelago.Create(AOwner: TComponent);
  2351. begin
  2352. inherited;
  2353. OnCreateLandTile := fOnCreateLandTile;
  2354. IsDefaultTile := FIsDefaultTile;
  2355. IslandDensity := 0.4;
  2356. FWaveAmplitude := 2;
  2357. FWaveSpeed := 20;
  2358. Sea := False; // Sea is drawn by the PostRender event
  2359. end;
  2360. procedure TGLFractalArchipelago.fOnCreateDefaultTile(heightData: TGLHeightData);
  2361. var
  2362. x, y: integer;
  2363. rasterLine: GLVectorGeometry.PSingleArray;
  2364. oldType: TGLHeightDataType;
  2365. begin
  2366. with heightData do
  2367. begin
  2368. DataState := hdsPreparing;
  2369. oldType := DataType;
  2370. Allocate(hdtSingle);
  2371. MaterialName := FMaterialName;
  2372. for y := 0 to heightData.Size - 1 do
  2373. begin
  2374. rasterLine := singleRaster[y];
  2375. for x := 0 to heightData.Size - 1 do
  2376. begin
  2377. rasterLine[x] := FSeaLevel;
  2378. end; // for
  2379. end; // for
  2380. if oldType <> hdtSingle then
  2381. DataType := oldType;
  2382. end; // with
  2383. end;
  2384. procedure TGLFractalArchipelago.fOnCreateLandTile(aX, aZ, aSeed: integer; var aLandscape: TGLLandTile);
  2385. begin
  2386. InitializeRandomGenerator(aSeed);
  2387. with TGLFractalHDS(aLandscape) do
  2388. begin
  2389. // Initialize the tile
  2390. Seed := random(MaxInt);
  2391. Depth := Self.fDepth;
  2392. Amplitude := random(FAmplitudeMax - FAmplitudeMin) + FAmplitudeMin;
  2393. Roughness := random * (FRoughnessMax - FRoughnessMin) + FRoughnessMin;
  2394. ApplyLighting(aLandscape);
  2395. ApplyTexture(aLandscape);
  2396. ApplyTopography(aLandscape);
  2397. Cyclic := True;
  2398. PrimerLandscape := True;
  2399. // Generate the landscape
  2400. PrimerIsland(SeaLevel - SeaTransparency, random * Amplitude / 2, FHeight);
  2401. // Pre-generate an island
  2402. BuildHeightField;
  2403. if ErosionByRain.Enabled then
  2404. DoErosionByRain;
  2405. if ErosionByLife.Enabled then
  2406. DoErosionByLife;
  2407. if ErosionBySea.Enabled then
  2408. DoErosionBySea;
  2409. if Sea then
  2410. DoSea;
  2411. BuildNormals;
  2412. if Lighting then
  2413. BuildLightMap
  2414. else
  2415. ClearLightMap;
  2416. BuildTexture;
  2417. FNormal := nil;
  2418. FLightMap := nil;
  2419. end; // with
  2420. end;
  2421. procedure TGLFractalArchipelago.FPostRenderSeaDynamic(var rci: TGLRenderContextInfo; var HeightDatas: TList);
  2422. // Code borrowed from Eric's Archipelago GLScene advanced demo
  2423. var
  2424. i, x, y, s, s2: integer;
  2425. t: single;
  2426. hd: TGLHeightData;
  2427. const
  2428. r = 0.75;
  2429. g = 0.75;
  2430. b = 1;
  2431. function WaterPhase(const px, py: single): single;
  2432. begin
  2433. Result := t * 1 + px * 0.16 + py * 0.09;
  2434. end;
  2435. procedure IssuePoint(rx, ry: integer);
  2436. var
  2437. px, py: single;
  2438. alpha, colorRatio, ca, sa: single;
  2439. begin
  2440. px := x + rx + s2;
  2441. py := y + ry + s2;
  2442. if hd.DataState = hdsNone then
  2443. begin
  2444. alpha := 1;
  2445. end
  2446. else
  2447. begin
  2448. alpha := (FSeaLevel - hd.SmallIntHeight(rx, ry)) * (1 / FSeaTransparency);
  2449. alpha := ClampValue(alpha, 0.5, 1);
  2450. end;
  2451. SinCos(WaterPhase(px, py) * FWaveSpeed, sa, ca);
  2452. colorRatio := 1 - alpha * 0.1;
  2453. gl.Color4f(r * colorRatio, g * colorRatio, b, alpha);
  2454. gl.TexCoord2f(px * 0.01 + 0.002 * sa, py * 0.01 + 0.0022 * ca - t * 0.01);
  2455. gl.Vertex3f(px, py, FSeaLevel + FWaveAmplitude * sa * VSF);
  2456. end;
  2457. begin
  2458. // if not WaterPlane then Exit;
  2459. t := ((GetTickCount - rhdsStartTime) / 10000);
  2460. FTerrainRenderer.MaterialLibrary.ApplyMaterial(FSeaMaterialName, rci);
  2461. repeat
  2462. // if not WasAboveWater then InverTGLFrontFace;
  2463. gl.PushAttrib(GL_ENABLE_BIT);
  2464. gl.Disable(GL_LIGHTING);
  2465. gl.Disable(GL_NORMALIZE);
  2466. gl.StencilFunc(GL_ALWAYS, 1, 255);
  2467. gl.StencilMask(255);
  2468. gl.StencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
  2469. gl.Enable(GL_STENCIL_TEST);
  2470. gl.Normal3f(0, 0, 1);
  2471. for i := 0 to HeightDatas.Count - 1 do
  2472. begin
  2473. hd := TGLHeightData(HeightDatas.List[i]);
  2474. if (hd.DataState = hdsReady) and (hd.HeightMin > FSeaLevel) then
  2475. continue;
  2476. x := hd.XLeft;
  2477. y := hd.YTop;
  2478. s := hd.Size - 1;
  2479. s2 := s div 2;
  2480. gl.Begin_(GL_TRIANGLE_FAN);
  2481. IssuePoint(s2, s2);
  2482. IssuePoint(0, 0);
  2483. IssuePoint(s2, 0);
  2484. IssuePoint(s, 0);
  2485. IssuePoint(s, s2);
  2486. IssuePoint(s, s);
  2487. IssuePoint(s2, s);
  2488. IssuePoint(0, s);
  2489. IssuePoint(0, s2);
  2490. IssuePoint(0, 0);
  2491. gl.End_;
  2492. end;
  2493. gl.StencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
  2494. gl.PopAttrib;
  2495. // if not WasAboveWater then InverTGLFrontFace;
  2496. // WaterPolyCount:=heightDatas.Count*8;
  2497. until not FTerrainRenderer.MaterialLibrary.UnApplyMaterial(rci);
  2498. end;
  2499. procedure TGLFractalArchipelago.FPostRenderSeaStatic(var rci: TGLRenderContextInfo; var HeightDatas: TList);
  2500. var
  2501. i, x, y, s, s2: integer;
  2502. hd: TGLHeightData;
  2503. t: single;
  2504. const
  2505. r = 0.75;
  2506. g = 0.75;
  2507. b = 1;
  2508. procedure IssuePoint(rx, ry: integer);
  2509. var
  2510. px, py: single;
  2511. alpha, colorRatio: single;
  2512. begin
  2513. px := x + rx + s2;
  2514. py := y + ry + s2;
  2515. if hd.DataState = hdsNone then
  2516. begin
  2517. alpha := 1;
  2518. end
  2519. else
  2520. begin
  2521. alpha := (FSeaLevel - hd.SmallIntHeight(rx, ry)) * (1 / FSeaTransparency);
  2522. alpha := ClampValue(alpha, 0.5, 1);
  2523. end;
  2524. colorRatio := 1 - alpha * 0.1;
  2525. gl.Color4f(r * colorRatio, g * colorRatio, b, alpha);
  2526. gl.TexCoord2f(px * 0.01, py * 0.01 + t);
  2527. gl.Vertex3f(px, py, FSeaLevel);
  2528. end;
  2529. begin
  2530. t := Frac(GetTickCount / 1000);
  2531. FTerrainRenderer.MaterialLibrary.ApplyMaterial(FSeaMaterialName, rci);
  2532. repeat
  2533. // if not WasAboveWater then InverTGLFrontFace;
  2534. gl.PushAttrib(GL_ENABLE_BIT);
  2535. gl.Disable(GL_LIGHTING);
  2536. gl.Disable(GL_NORMALIZE);
  2537. gl.StencilFunc(GL_ALWAYS, 1, 255);
  2538. gl.StencilMask(255);
  2539. gl.StencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
  2540. gl.Enable(GL_STENCIL_TEST);
  2541. gl.Normal3f(0, 0, 1);
  2542. for i := 0 to HeightDatas.Count - 1 do
  2543. begin
  2544. hd := TGLHeightData(HeightDatas.List[i]);
  2545. if (hd.DataState = hdsReady) and (hd.HeightMin > FSeaLevel) then
  2546. continue;
  2547. x := hd.XLeft;
  2548. y := hd.YTop;
  2549. s := hd.Size - 1;
  2550. s2 := s div 2;
  2551. gl.Begin_(GL_TRIANGLE_FAN);
  2552. IssuePoint(s2, s2);
  2553. IssuePoint(0, 0);
  2554. IssuePoint(s2, 0);
  2555. IssuePoint(s, 0);
  2556. IssuePoint(s, s2);
  2557. IssuePoint(s, s);
  2558. IssuePoint(s2, s);
  2559. IssuePoint(0, s);
  2560. IssuePoint(0, s2);
  2561. IssuePoint(0, 0);
  2562. gl.End_;
  2563. end;
  2564. gl.StencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
  2565. gl.PopAttrib;
  2566. // if not WasAboveWater then InverTGLFrontFace;
  2567. // WaterPolyCount:=heightDatas.Count*8;
  2568. until not FTerrainRenderer.MaterialLibrary.UnApplyMaterial(rci);
  2569. end;
  2570. function TGLFractalArchipelago.GetIslandDensity: single;
  2571. begin
  2572. Result := FLandTileDensity;
  2573. end;
  2574. procedure TGLFractalArchipelago.SetAmplitudeMax(const Value: integer);
  2575. begin
  2576. FAmplitudeMax := Value;
  2577. end;
  2578. procedure TGLFractalArchipelago.SetAmplitudeMin(const Value: integer);
  2579. begin
  2580. FAmplitudeMin := Value;
  2581. end;
  2582. procedure TGLFractalArchipelago.SetDepth(const Value: integer);
  2583. begin
  2584. fDepth := Value;
  2585. SetSize(Round(IntPower(2, fDepth)));
  2586. end;
  2587. procedure TGLFractalArchipelago.SetIslandDensity(const Value: single);
  2588. begin
  2589. LandTileDensity := Value;
  2590. end;
  2591. procedure TGLFractalArchipelago.SetRoughnessMax(const Value: single);
  2592. begin
  2593. FRoughnessMax := Value;
  2594. end;
  2595. procedure TGLFractalArchipelago.SetRoughnessMin(const Value: single);
  2596. begin
  2597. FRoughnessMin := Value;
  2598. end;
  2599. procedure TGLFractalArchipelago.SetSeaDynamic(const Value: boolean);
  2600. begin
  2601. FSeaDynamic := Value;
  2602. if FSeaDynamic then
  2603. FTerrainRenderer.OnHeightDataPostRender := FPostRenderSeaDynamic
  2604. else
  2605. FTerrainRenderer.OnHeightDataPostRender := FPostRenderSeaStatic;
  2606. end;
  2607. procedure TGLFractalArchipelago.SetSeaMaterialName(const Value: string);
  2608. begin
  2609. FSeaMaterialName := Value;
  2610. end;
  2611. procedure TGLFractalArchipelago.SetTerrainRenderer(const Value: TGLTerrainRenderer);
  2612. begin
  2613. inherited;
  2614. SeaDynamic := FSeaDynamic; // Called to hook the PostRender event handler
  2615. end;
  2616. procedure TGLFractalArchipelago.SetWaveAmplitude(const Value: single);
  2617. begin
  2618. FWaveAmplitude := Value;
  2619. end;
  2620. procedure TGLFractalArchipelago.SetWaveSpeed(const Value: single);
  2621. begin
  2622. FWaveSpeed := Value;
  2623. end;
  2624. (***************************************************************
  2625. ******* RANDOM HDS ALGORITHMS ********
  2626. ***************************************************************)
  2627. (* Fractal algorithm based on the middle-point displacement method. It is built in
  2628. a way that it can be juxtaposed seamlessly to itself (cyclic boundaries) *)
  2629. procedure FractalMiddlePointHDS(const aDepth, aSeed, aAmplitude: integer; const aRoughness: single; aCyclic: boolean;
  2630. var z: TMapOfSingle; var MinZ, MaxZ: single);
  2631. var
  2632. iter, Stp, stp2: integer;
  2633. i, j: integer;
  2634. dz: single;
  2635. Size: integer;
  2636. // Fill variables only if they have not been predefined
  2637. procedure Let(var z: single; const Value: single);
  2638. begin
  2639. if z = Empty then
  2640. z := Value;
  2641. end;
  2642. // Fill variables only if they have not been predefined
  2643. function Get(const x, y: integer; var Value: single): boolean;
  2644. begin
  2645. Value := z[x, y];
  2646. Result := (Value = Empty);
  2647. end;
  2648. function Centre(const x, y, Stp: integer): single;
  2649. begin
  2650. Result := z[x - Stp, y - Stp];
  2651. Result := Result + z[x - Stp, y + Stp];
  2652. Result := Result + z[x + Stp, y - Stp];
  2653. Result := Result + z[x + Stp, y + Stp];
  2654. Result := Result * 0.25;
  2655. if MinZ > Result then
  2656. MinZ := Result;
  2657. if MaxZ < Result then
  2658. MaxZ := Result;
  2659. end;
  2660. function Side(const x, y, Stp: integer): single;
  2661. var
  2662. n: integer;
  2663. begin
  2664. n := 0;
  2665. Result := 0;
  2666. if y - Stp >= 0 then
  2667. begin
  2668. Result := Result + z[x, y - Stp];
  2669. Inc(n);
  2670. end;
  2671. if y + Stp <= Size then
  2672. begin
  2673. Result := Result + z[x, y + Stp];
  2674. Inc(n);
  2675. end;
  2676. if x - Stp >= 0 then
  2677. begin
  2678. Result := Result + z[x - Stp, y];
  2679. Inc(n);
  2680. end;
  2681. if x + Stp <= Size then
  2682. begin
  2683. Result := Result + z[x + Stp, y];
  2684. Inc(n);
  2685. end;
  2686. Result := Result / n;
  2687. if MinZ > Result then
  2688. MinZ := Result;
  2689. if MaxZ < Result then
  2690. MaxZ := Result;
  2691. end;
  2692. begin
  2693. InitializeRandomGenerator(aSeed);
  2694. Size := High(z);
  2695. dz := aAmplitude * VSF;
  2696. MinZ := 1E38;
  2697. MaxZ := -1E38;
  2698. if aCyclic then
  2699. begin
  2700. Let(z[0, 0], 0);
  2701. Let(z[0, Size], z[0, 0]);
  2702. Let(z[Size, 0], z[0, 0]);
  2703. Let(z[Size, Size], z[0, 0]);
  2704. // Build Height field
  2705. for iter := 1 TO aDepth do
  2706. begin // iterations
  2707. Stp := Round(Size / IntPower(2, (iter - 1))); // step
  2708. stp2 := Stp div 2; // half step
  2709. dz := dz * aRoughness;
  2710. i := stp2;
  2711. repeat
  2712. j := stp2;
  2713. repeat // Centre
  2714. if z[i, j] = Empty then
  2715. begin
  2716. z[i, j] := Centre(i, j, stp2);
  2717. z[i, j] := z[i, j] + (random * dz * 2 - dz) * 1.4;
  2718. end; // if
  2719. Inc(j, Stp);
  2720. until j > Size - stp2 + 1;
  2721. Inc(i, Stp);
  2722. until i > Size - stp2 + 1;
  2723. i := stp2;
  2724. repeat
  2725. j := 0;
  2726. repeat // Sides
  2727. if z[i, j] = Empty then
  2728. begin
  2729. z[i, j] := Side(i, j, stp2);
  2730. z[i, j] := z[i, j] + random * dz * 2 - dz;
  2731. end; // if
  2732. if z[j, i] = Empty then
  2733. begin
  2734. z[j, i] := Side(j, i, stp2);
  2735. z[j, i] := z[j, i] + random * dz * 2 - dz;
  2736. end; // if
  2737. Inc(j, Stp);
  2738. until j >= Size;
  2739. Let(z[Size, i], z[0, i]);
  2740. Let(z[i, Size], z[i, 0]);
  2741. Inc(i, Stp);
  2742. until i > Size - stp2 + 1;
  2743. end; // for iter
  2744. end // if Cyclic
  2745. else
  2746. begin // Non-cyclic landscape
  2747. Let(z[0, 0], random * dz * 2 - dz);
  2748. Let(z[0, Size], random * dz * 2 - dz);
  2749. Let(z[Size, 0], random * dz * 2 - dz);
  2750. Let(z[Size, Size], random * dz * 2 - dz);
  2751. // Build Height field
  2752. for iter := 1 to aDepth do
  2753. begin // iterations
  2754. Stp := Round(Size / IntPower(2, (iter - 1))); // step
  2755. stp2 := Stp div 2; // half step
  2756. dz := dz * aRoughness;
  2757. i := stp2;
  2758. repeat
  2759. j := stp2;
  2760. repeat // Centre
  2761. if z[i, j] = Empty then
  2762. begin
  2763. z[i, j] := Centre(i, j, stp2);
  2764. z[i, j] := z[i, j] + (random * dz * 2 - dz) * 1.4;
  2765. end;
  2766. Inc(j, Stp);
  2767. until j > Size - stp2 + 1;
  2768. Inc(i, Stp);
  2769. until i > Size - stp2 + 1;
  2770. i := stp2;
  2771. repeat
  2772. j := 0;
  2773. repeat // Sides
  2774. if z[i, j] = Empty then
  2775. begin
  2776. z[i, j] := Side(i, j, stp2);
  2777. z[i, j] := z[i, j] + random * dz * 2 - dz;
  2778. end; // if
  2779. if z[j, i] = Empty then
  2780. begin
  2781. z[j, i] := Side(j, i, stp2);
  2782. z[j, i] := z[j, i] + random * dz * 2 - dz;
  2783. end; // if
  2784. Inc(j, Stp);
  2785. until j > Size;
  2786. Inc(i, Stp);
  2787. until i > Size - stp2 + 1;
  2788. end; // for iter
  2789. end; // else Cyclic
  2790. end;
  2791. (***************************************************************
  2792. ******* PREDEFINED HEIGHT-FIELD ********
  2793. ***************************************************************)
  2794. procedure PrimerNull(var z: TMapOfSingle);
  2795. // Empty field
  2796. var
  2797. x, y: integer;
  2798. Size: integer;
  2799. begin
  2800. Size := High(z);
  2801. for y := 0 to Size do
  2802. begin
  2803. for x := 0 to Size do
  2804. begin
  2805. z[x, y] := Empty;
  2806. end; // for
  2807. end; // for
  2808. end;
  2809. (* Ensure that the border of the tile is low (below sea level) and the middle
  2810. is high. *)
  2811. procedure PrimerIsland(LowZ, HighZ: single; var z: TMapOfSingle);
  2812. var
  2813. i: integer;
  2814. Size: integer;
  2815. begin
  2816. Size := High(z);
  2817. PrimerNull(z);
  2818. HighZ := HighZ * VSF;
  2819. LowZ := LowZ * VSF;
  2820. z[Size div 2, Size div 2] := HighZ;
  2821. for i := 0 to Size do
  2822. begin
  2823. z[i, 0] := LowZ;
  2824. z[0, i] := LowZ;
  2825. z[Size, i] := LowZ;
  2826. z[i, Size] := LowZ;
  2827. end; // for i
  2828. end;
  2829. //----------------------------------------------
  2830. initialization
  2831. //----------------------------------------------
  2832. rhdsStartTime := GetTickCount;
  2833. end.