GLS.RandomHDS.pas 92 KB

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