GLS.RandomHDS.pas 91 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134
  1. //
  2. // The multimedia graphics platform 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. GLS.OpenGLTokens,
  52. GLS.Scene,
  53. GLS.VectorTypes,
  54. GLS.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. end;
  1287. procedure TGLCustomRandomHDS.DoErosionByLife;
  1288. var
  1289. x, y, i: integer;
  1290. z, z1: single;
  1291. begin
  1292. // Smoothing by a 3-by-3 mean filter
  1293. FTask := 'Erosion by life';
  1294. FTaskProgress := 0;
  1295. for y := 0 to FSize do
  1296. begin
  1297. FTaskProgress := Round(y / (FSize) * 100);
  1298. for x := 0 to FSize do
  1299. begin
  1300. Application.ProcessMessages;
  1301. z := FHeight[x, y] * FErosionByLife.Robustness;
  1302. z1 := FErosionByLife.Robustness;
  1303. for i := 0 to 7 do
  1304. begin
  1305. z := z + Heights[x + NeighX[i], y + NeighY[i]] * NeighW[i];
  1306. z1 := z1 + NeighW[i];
  1307. end; // for i
  1308. FHeight[x, y] := z / z1;
  1309. end; // for x
  1310. end; // for y
  1311. end;
  1312. procedure TGLCustomRandomHDS.DoErosionByRain;
  1313. const
  1314. Ks = 0.001; // Soil solubility
  1315. var
  1316. j: integer;
  1317. x0, y0: integer;
  1318. x, y: integer;
  1319. x1, y1: integer;
  1320. minx, miny: integer;
  1321. z, z1: single;
  1322. MinZ: single;
  1323. dz, mindz: single;
  1324. Charge: double;
  1325. From, Next: integer;
  1326. begin
  1327. FTask := 'Rain erosion simulation';
  1328. FTaskProgress := 0;
  1329. minx := 0;
  1330. miny := 0;
  1331. MinZ := 0;
  1332. Next := 0;
  1333. // Rain
  1334. for y0 := 0 to FSize do
  1335. begin
  1336. FTaskProgress := Round(y0 / (FSize) * 100);
  1337. for x0 := 0 to FSize do
  1338. begin
  1339. Application.ProcessMessages;
  1340. x := x0;
  1341. y := y0;
  1342. z := StandardisedHeight(x, y);
  1343. Charge := 0;
  1344. From := -1;
  1345. while (FHeight[x, y] > FSeaLevel) // Not in the sea
  1346. do
  1347. begin
  1348. mindz := MaxInt;
  1349. for j := 0 to 7 do
  1350. begin // Look for the largest slope
  1351. if j = From then
  1352. continue; // Never go backward
  1353. x1 := (FSize + x + NeighX[j]) mod FSize; // Cyclic landscape
  1354. y1 := (FSize + y + NeighY[j]) mod FSize;
  1355. z1 := StandardisedHeight(x1, y1);
  1356. dz := (z1 - z) * NeighW[j];
  1357. if dz < mindz then
  1358. begin
  1359. minx := x1;
  1360. miny := y1;
  1361. MinZ := z1;
  1362. mindz := dz;
  1363. Next := j;
  1364. end; // if
  1365. end; // for j
  1366. if (StandardisedHeight(minx, miny) <= SeaLevel) then
  1367. break; // In the sea or out of map
  1368. if MinZ < z then
  1369. begin
  1370. FHeight[x, y] := FHeight[x, y] - FErosionByRain.ErosionRate * Ks * FRangeHeight; // Erosion
  1371. x := minx;
  1372. y := miny;
  1373. z := MinZ;
  1374. From := (Next + 4) mod 8; // Opposite direction
  1375. Charge := Charge + 1;
  1376. end // if
  1377. else
  1378. begin // Fallen into a pool? Deposit the charge
  1379. FHeight[x, y] := FHeight[x, y] + MinFloat(MinZ - z, FErosionByRain.DepositRate * Ks * FRangeHeight * Charge);
  1380. break; // Go to next rain drop
  1381. end; // else
  1382. end; // while
  1383. end; // for x0
  1384. end; // for y0
  1385. end; // *)
  1386. (*
  1387. Variants:
  1388. procedure TGLBaseRandomHDS.DoErosionByRain(const Intensity: single);
  1389. const
  1390. NeighX :array[0..7] of integer=(-1, 0, 1, 1, 1, 0,-1,-1);
  1391. NeighY :array[0..7] of integer=(-1,-1,-1, 0, 1, 1, 1, 0);
  1392. NeighW :array[0..7] of single=(1/1.4142,1,1/1.4142,1,1/1.4142,1,1/1.4142,1);
  1393. type
  1394. tFlow=record
  1395. NextX,NextY :integer;
  1396. Slope :single;
  1397. Erosion :integer;
  1398. end;
  1399. var
  1400. Flow :array of array of tFlow;
  1401. i,j,jj,swap :integer;
  1402. x0,y0 :integer;
  1403. x,y :integer;
  1404. x1,y1 :integer;
  1405. minx,miny :integer;
  1406. z,z1,minz :single;
  1407. Charge :integer;
  1408. N :integer;
  1409. From,Next :integer;
  1410. Sig :integer;
  1411. c :double;
  1412. OldSlope :single;
  1413. dz,mindz :single;
  1414. begin
  1415. c:=1/VSF/sqrt(sqr(Scale.X)+sqr(Scale.Z));
  1416. // Water flow map computation
  1417. SetLength(Flow,fSize+1,fSize+1);
  1418. for y:=0 to fSize do begin
  1419. for x:=0 to fSize do begin
  1420. mindz:=MaxInt;
  1421. Sig:=Sign(random*2-1);
  1422. z:=fHeight[x,y];
  1423. for jj:=0 to 7 do begin // Look for the largest slope
  1424. j:=(8+Sig*jj) mod 8;
  1425. x1:=x+NeighX[j];
  1426. y1:=y+NeighY[j];
  1427. try z1:=Height[x1,y1];
  1428. dz:=(z1-z)*NeighW[j];
  1429. if dz+random*0.03*fRangeHeight<mindz then begin
  1430. minx:=x1;
  1431. miny:=y1;
  1432. minz:=z1;
  1433. mindz:=dz;
  1434. Next:=j;
  1435. end;//if
  1436. except // Out of the map? Then go to next rain drop
  1437. Flow[x,y].NextX:=-99;
  1438. Break;
  1439. end;
  1440. with Flow[x,y] do begin
  1441. Slope:=ArcTan((minz-z)*c);
  1442. if Slope>0 then NextX:=-99
  1443. else begin
  1444. NextX:=minx;
  1445. NextY:=miny;
  1446. Erosion:=0;
  1447. end;//if
  1448. end;//with
  1449. end;//for j
  1450. end;//for
  1451. end;//for
  1452. From:=0;
  1453. //Rain
  1454. for y0:=0 to fSize do begin
  1455. for x0:=0 to fSize do begin
  1456. x:=x0;
  1457. y:=y0;
  1458. OldSlope:=0;
  1459. while (x<>-99)and(fCover[x,y]>0) do begin // Not in the sea
  1460. with Flow[x,y] do begin
  1461. if (Slope*2<OldSlope) then begin
  1462. Dec(Erosion);
  1463. x:=NextX;
  1464. y:=NextY;
  1465. OldSlope:=Slope;
  1466. end//if
  1467. else begin
  1468. //Inc(Erosion);
  1469. Break;
  1470. end;//else
  1471. end;//with
  1472. end;//while
  1473. end;//for x0
  1474. end;//for y0
  1475. //Apply erosion
  1476. for y:=0 to fSize do begin
  1477. for x:=0 to fSize do begin
  1478. //fHeight[x,y]:=fHeight[x,y]+Flow[x,y].Erosion*0.002*Intensity*fRangeHeight;
  1479. fHeight[x,y]:=(Flow[x,y].Erosion)*100+50;
  1480. end;//for
  1481. end;//for
  1482. Flow:=nil;
  1483. end; // *)
  1484. (* procedure TGLBaseRandomHDS.DoErosionByRain(const Intensity: single);
  1485. const
  1486. NeighX:array[0..7] of integer=(-1, 0, 1, 1, 1, 0,-1,-1);
  1487. NeighY:array[0..7] of integer=(-1,-1,-1, 0, 1, 1, 1, 0);
  1488. var
  1489. Erosion :array of array of single;
  1490. Flow :array[0..7] of single;
  1491. FlowSum :single;
  1492. j :integer;
  1493. x,y :integer;
  1494. x1,y1 :integer;
  1495. z,z1 :single;
  1496. c :single;
  1497. begin
  1498. c:=1/VSF; // Vertical scale factor
  1499. SetLength(Erosion,fSize+2,fSize+2);
  1500. for y:=0 to fSize+1 do for x:=0 to fSize+1 do Erosion[x,y]:=0;
  1501. //Erosion computation
  1502. for y:=0 to fSize+1 do begin
  1503. for x:=0 to fSize+1 do begin
  1504. z:=fHeight[x,y];
  1505. FlowSum:=0;
  1506. for j:=0 to 7 do begin // Flow to adjacent cells
  1507. x1:=x+NeighX[j];
  1508. y1:=y+NeighY[j];
  1509. try
  1510. z1:=Height[x1,y1]+random*0;
  1511. if z1<z then begin
  1512. Flow[j]:=ArcTan((z-z1)*c);
  1513. FlowSum:=FlowSum+Flow[j];
  1514. end//if
  1515. else Flow[j]:=0;
  1516. except
  1517. Flow[j]:=0;
  1518. end;//except
  1519. end;//for j
  1520. if FlowSum>0 then begin // Erosion and deposition
  1521. Erosion[x,y]:=Erosion[x,y]-1; // Erosion
  1522. for j:=0 to 7 do begin
  1523. if Flow[j]>1e-3 then begin
  1524. x1:=x+NeighX[j];
  1525. y1:=y+NeighY[j];
  1526. Erosion[x1,y1]:=Erosion[x1,y1]+Flow[j]/FlowSum; // Partial deposition
  1527. end;//if
  1528. end;//for
  1529. end;//if
  1530. end;//for x
  1531. end;//for y
  1532. //Apply erosion to each cell
  1533. for y:=0 to fSize do begin
  1534. for x:=0 to fSize do begin
  1535. fHeight[x,y]:=fHeight[x,y]+Erosion[x,y]*0.005*Intensity*fRangeHeight;
  1536. //fHeight[x,y]:=(Erosion[x,y])*100+50;
  1537. end;//for
  1538. end;//for
  1539. Erosion:=nil;
  1540. end; // *)
  1541. (* procedure TGLBaseRandomHDS.DoErosionByRain(const Intensity: single);
  1542. const
  1543. NeighX:array[0..7] of integer=(-1, 0, 1, 1, 1, 0,-1,-1);
  1544. NeighY:array[0..7] of integer=(-1,-1,-1, 0, 1, 1, 1, 0);
  1545. var
  1546. Erosion :array of array of single;
  1547. i,j,jj :integer;
  1548. x,y :integer;
  1549. x1,y1 :integer;
  1550. x2,y2 :integer;
  1551. z,z1,z2,dz :single;
  1552. begin
  1553. SetLength(Erosion,fSize+2,fSize+2);
  1554. for i:=1 to 1 do begin
  1555. //for y:=0 to fSize+1 do for x:=0 to fSize+1 do Erosion[x,y]:=0;
  1556. //Erosion computation
  1557. for y:=5 to fSize-4 do begin
  1558. for x:=5 to fSize-4 do begin
  1559. z:=fHeight[x,y];
  1560. dz:=1;
  1561. for jj:=1 to 2 do begin // Flow to adjacent cells
  1562. j:=jj*2;
  1563. x1:=x+NeighX[j]*5;
  1564. y1:=y+NeighY[j]*5;
  1565. x2:=x+NeighX[j+4]*5;
  1566. y2:=y+NeighY[j+4]*5;
  1567. try
  1568. z1:=Height[x1,y1]+random*0;
  1569. z2:=Height[x2,y2]+random*0;
  1570. dz:=dz*Sign(z-(z1+z2)/2);
  1571. except
  1572. end;//except
  1573. end;//for j
  1574. Erosion[x,y]:=dz;
  1575. end;//for x
  1576. end;//for y
  1577. //Apply erosion to each cell
  1578. for y:=0 to fSize do begin
  1579. for x:=0 to fSize do begin
  1580. fHeight[x,y]:=fHeight[x,y]+Erosion[x,y]*100*Intensity;
  1581. //fHeight[x,y]:=(Erosion[x,y])*1+50;
  1582. end;//for
  1583. end;//for
  1584. end;//for i
  1585. Erosion:=nil;
  1586. end; // *)
  1587. procedure TGLCustomRandomHDS.DoErosionBySea;
  1588. var
  1589. i, j: integer;
  1590. begin
  1591. for i := 0 to FSize do
  1592. begin
  1593. for j := 0 to FSize do
  1594. begin
  1595. Application.ProcessMessages;
  1596. if abs(FHeight[i, j] - FSeaLevel) < FErosionBySea.BeachHeight * VSF then
  1597. begin
  1598. FHeight[i, j] := FSeaLevel + (FHeight[i, j] - FSeaLevel) * 0.3;
  1599. end; // if
  1600. end; // for
  1601. end; // for
  1602. end;
  1603. procedure TGLCustomRandomHDS.DoSea;
  1604. var
  1605. i, j: integer;
  1606. begin
  1607. for i := 0 to FSize do
  1608. begin
  1609. for j := 0 to FSize do
  1610. begin
  1611. // if fHeight[i,j]<Lvl then fHeight[i,j]:=Lvl-random*wave;
  1612. if FHeight[i, j] < FSeaLevel - FSeaTransparency then
  1613. FHeight[i, j] := FSeaLevel - 1 // Lvl-c-random*wave
  1614. else if FHeight[i, j] < FSeaLevel then
  1615. FHeight[i, j] := FSeaLevel - (FSeaLevel - FHeight[i, j]) / FSeaTransparency;
  1616. end; // for
  1617. end; // for
  1618. end;
  1619. procedure TGLCustomRandomHDS.DoSteps;
  1620. var
  1621. i, j: integer;
  1622. Stp: single;
  1623. begin
  1624. Stp := (FMaxHeight - FSeaLevel) / FSteps.Count; // Step height
  1625. for i := 0 to FSize do
  1626. begin
  1627. for j := 0 to FSize do
  1628. begin
  1629. FHeight[i, j] := Round(FHeight[i, j] / Stp) * Stp;
  1630. end; // for
  1631. end; // for
  1632. end;
  1633. function TGLCustomRandomHDS.GetHeight(x, y: integer): single;
  1634. begin
  1635. FIntegerConstrain(x, y);
  1636. Result := FHeight[x, y];
  1637. end;
  1638. procedure TGLCustomRandomHDS.GetTerrainBounds(var l, t, r, b: single);
  1639. begin
  1640. l := 0;
  1641. b := 0;
  1642. t := FSize;
  1643. r := FSize;
  1644. end;
  1645. // Copied from GLS.HeightData.InterpolatedHeight
  1646. function TGLCustomRandomHDS.Interpolate(x, y: single): single;
  1647. var
  1648. ix, iy: integer;
  1649. h1, h2, h3: single;
  1650. begin
  1651. ix := Trunc(x);
  1652. x := Frac(x);
  1653. iy := Trunc(y);
  1654. y := Frac(y);
  1655. if x > y then
  1656. begin
  1657. // top-right triangle
  1658. h1 := Heights[ix + 1, iy];
  1659. h2 := Heights[ix, iy];
  1660. h3 := Heights[ix + 1, iy + 1];
  1661. Result := h1 + (h2 - h1) * (1 - x) + (h3 - h1) * y;
  1662. end
  1663. else
  1664. begin
  1665. // bottom-left triangle
  1666. h1 := Heights[ix, iy + 1];
  1667. h2 := Heights[ix + 1, iy + 1];
  1668. h3 := Heights[ix, iy];
  1669. Result := h1 + (h2 - h1) * (x) + (h3 - h1) * (1 - y);
  1670. end;
  1671. end;
  1672. function TGLCustomRandomHDS.PointInMap(const x, y: single): boolean;
  1673. begin
  1674. Result := (x >= 0) and (x <= FSize) and (y >= 0) and (y <= FSize);
  1675. end;
  1676. function TGLCustomRandomHDS.Normal(const Position: TGLVector): TGLVector;
  1677. var
  1678. x, y: integer;
  1679. begin
  1680. if (FNormal <> nil) then
  1681. begin
  1682. Result := FTerrainRenderer.AbsoluteToLocal(Position);
  1683. x := Round(Result.x);
  1684. y := Round(Result.y);
  1685. FIntegerConstrain(x, y);
  1686. Result := FNormal[x, y];
  1687. end // if
  1688. else
  1689. raise EAccessViolation.Create('No normal array computed.');
  1690. end;
  1691. function TGLCustomRandomHDS.PointInMap(const x, y: integer): boolean;
  1692. begin
  1693. Result := (x >= 0) and (x <= FSize) and (y >= 0) and (y <= FSize);
  1694. end;
  1695. function TGLCustomRandomHDS.Scale: TGLCoordinates;
  1696. begin
  1697. try
  1698. Result := FTerrainRenderer.Scale;
  1699. except
  1700. raise EAccessViolation.Create('No TerrainRenderer defined');
  1701. end;
  1702. end;
  1703. procedure TGLCustomRandomHDS.SetCyclic(const Value: boolean);
  1704. begin
  1705. FCyclic := Value;
  1706. if FCyclic then
  1707. begin
  1708. FIntegerConstrain := CyclicClamp;
  1709. FSingleConstrain := CyclicClamp;
  1710. if FTerrainRenderer <> nil then
  1711. FTerrainRenderer.OnGetTerrainBounds := nil;
  1712. end
  1713. else
  1714. begin
  1715. FIntegerConstrain := BoundaryClamp;
  1716. FSingleConstrain := BoundaryClamp;
  1717. if FTerrainRenderer <> nil then
  1718. FTerrainRenderer.OnGetTerrainBounds := GetTerrainBounds;
  1719. end; // else
  1720. end;
  1721. procedure TGLCustomRandomHDS.SetHeight(x, y: integer; const Value: single);
  1722. begin
  1723. FIntegerConstrain(x, y);
  1724. FHeight[x, y] := Value;
  1725. end;
  1726. procedure TGLCustomRandomHDS.SetSize(const aSize: integer);
  1727. var
  1728. Tile: integer;
  1729. begin
  1730. FSize := aSize;
  1731. if FSize > 32 then
  1732. Tile := 32
  1733. else
  1734. Tile := Round(IntPower(2, Trunc(ln(FSize - 1) / ln(2))));
  1735. SetLength(FHeight, FSize + 1, FSize + 1);
  1736. SetLength(FNormal, FSize + 1, FSize + 1);
  1737. MaxPoolSize := sqr(FSize) * SizeOf(smallint);
  1738. if FTerrainRenderer <> nil then
  1739. begin
  1740. FTerrainRenderer.TileSize := Tile;
  1741. FTerrainRenderer.TilesPerTexture := FSize div FTerrainRenderer.TileSize;
  1742. end; // if
  1743. end;
  1744. procedure TGLCustomRandomHDS.SetTerrainRenderer(const Value: TGLTerrainRenderer);
  1745. begin
  1746. FTerrainRenderer := Value;
  1747. if not FSlave then
  1748. begin
  1749. FTerrainRenderer.OnGetTerrainBounds := GetTerrainBounds;
  1750. FTerrainRenderer.HeightDataSource := Self;
  1751. end; // if
  1752. end;
  1753. function TGLCustomRandomHDS.StandardisedHeight(const x, y: integer): single;
  1754. begin
  1755. Result := (Heights[x, y] - FMinHeight) / FRangeHeight * 1000;
  1756. end;
  1757. procedure TGLCustomRandomHDS.StartPreparingData(heightData: TGLHeightData);
  1758. var
  1759. x, y, x0, y0: integer;
  1760. rasterLine: GLS.HeightData.PSmallIntArray;
  1761. oldType: TGLHeightDataType;
  1762. begin
  1763. with heightData do
  1764. begin
  1765. DataState := hdsPreparing;
  1766. oldType := DataType;
  1767. Allocate(hdtSmallInt);
  1768. if XLeft >= 0 then
  1769. x0 := XLeft mod (FSize)
  1770. else
  1771. x0 := (FSize + (XLeft mod (FSize))) mod (FSize);
  1772. if YTop >= 0 then
  1773. y0 := YTop mod (FSize)
  1774. else
  1775. y0 := (FSize + (YTop mod (FSize))) mod (FSize);
  1776. if FLandCover then
  1777. begin
  1778. MaterialName := Format('%s%d%d', [Self.Name, x0 div (heightData.Size - 1), y0 div (heightData.Size - 1)]);
  1779. TextureCoordinatesMode := tcmLocal;
  1780. TextureCoordinatesScale := TexPointMake((Self.FSize) / (heightData.Size - 1), (Self.FSize) / (heightData.Size - 1));
  1781. end // if
  1782. else
  1783. begin
  1784. MaterialName := Self.FMaterialName;
  1785. TextureCoordinatesMode := tcmLocal;
  1786. TextureCoordinatesScale := TexPointMake(FTextureScale, FTextureScale);
  1787. end; // else
  1788. for y := y0 to y0 + heightData.Size - 1 do
  1789. begin
  1790. rasterLine := smallintRaster[y - y0];
  1791. for x := x0 to x0 + heightData.Size - 1 do
  1792. begin
  1793. rasterLine[x - x0] := Round(FHeight[x, y]);
  1794. end; // for
  1795. end; // for
  1796. HeightMin := MinHeight;
  1797. HeightMax := MaxHeight;
  1798. DataState := hdsReady;
  1799. if oldType <> hdtSmallInt then
  1800. DataType := oldType;
  1801. end; // with
  1802. // inherited;
  1803. end; // *)
  1804. function TGLCustomRandomHDS.XMoveBoundary: single;
  1805. begin
  1806. Result := FSize * Scale.x * 0.95;
  1807. end;
  1808. function TGLCustomRandomHDS.ZMoveBoundary: single;
  1809. begin
  1810. Result := FSize * Scale.y * 0.95;
  1811. end;
  1812. procedure TGLCustomRandomHDS.SetKeepNormals(const Value: boolean);
  1813. begin
  1814. FKeepNormals := Value;
  1815. end;
  1816. // --------------------------------------
  1817. // TGLFractalHDS
  1818. // --------------------------------------
  1819. procedure TGLFractalHDS.BuildHeightField(const aDepth, aSeed, aAmplitude: integer);
  1820. begin
  1821. fDepth := aDepth;
  1822. FSeed := aSeed;
  1823. fAmplitude := aAmplitude;
  1824. BuildHeightField;
  1825. end;
  1826. procedure TGLFractalHDS.BuildHeightField;
  1827. begin
  1828. FractalMiddlePointHDS(fDepth, FSeed, fAmplitude, fRoughness, FCyclic, FHeight, FMinHeight, FMaxHeight);
  1829. FRangeHeight := FMaxHeight - FMinHeight;
  1830. Scale.x := 1;
  1831. Scale.y := 1;
  1832. Scale.z := FSize / VSF;
  1833. end;
  1834. constructor TGLFractalHDS.Create(AOwner: TComponent);
  1835. begin
  1836. inherited;
  1837. Depth := 4;
  1838. FSea := True;
  1839. Amplitude := 50;
  1840. fRoughness := 0.4;
  1841. end;
  1842. procedure TGLFractalHDS.SetAmplitude(const Value: integer);
  1843. begin
  1844. fAmplitude := Value;
  1845. FMinHeight := -fAmplitude / 2 * VSF;
  1846. FMaxHeight := -FMinHeight;
  1847. FRangeHeight := fAmplitude * VSF;
  1848. end;
  1849. procedure TGLFractalHDS.SetDepth(const Value: integer);
  1850. begin
  1851. fDepth := Value;
  1852. SetSize(Round(IntPower(2, fDepth)));
  1853. end;
  1854. procedure TGLFractalHDS.SetRoughness(const Value: single);
  1855. begin
  1856. fRoughness := Value;
  1857. end;
  1858. //-----------------------------------
  1859. // TGLRandomLandscape
  1860. //-----------------------------------
  1861. procedure TGLTiledRndLandscape.ApplyLighting(var aLandTile: TGLLandTile);
  1862. begin
  1863. with aLandTile do
  1864. begin
  1865. Lighting := Self.FLighting;
  1866. LightColor := Self.FLightColor;
  1867. LightDirection := Self.FLightDirection;
  1868. LightSmoothing := Self.FLightSmoothing;
  1869. Shadows := Self.Shadows;
  1870. end; // with
  1871. end;
  1872. procedure TGLTiledRndLandscape.ApplyTexture(var aLandTile: TGLLandTile);
  1873. begin
  1874. with aLandTile do
  1875. begin
  1876. LandCover := Self.LandCover;
  1877. MaterialName := Self.FMaterialName;
  1878. TextureScale := Self.FTextureScale;
  1879. if Assigned(Self.OnDrawTexture) then
  1880. FOnDrawTexture := Self.OnDrawTexture;
  1881. end; // with
  1882. end;
  1883. procedure TGLTiledRndLandscape.ApplyTopography(var aLandTile: TGLLandTile);
  1884. begin
  1885. with aLandTile do
  1886. begin
  1887. ErosionByFraction := Self.FErosionByFraction;
  1888. ErosionByLife := Self.FErosionByLife;
  1889. ErosionByRain := Self.FErosionByRain;
  1890. ErosionBySea := Self.FErosionBySea;
  1891. FSea := Self.FSea;
  1892. FSeaLevel := Self.FSeaLevel;
  1893. FSeaTransparency := Self.FSeaTransparency;
  1894. end; // with
  1895. end;
  1896. procedure TGLTiledRndLandscape.BoundaryClamp(var x, z: single);
  1897. begin
  1898. ClampValue(x, 0, FExtentX * fLandTileSize);
  1899. ClampValue(z, 0, FExtentZ * fLandTileSize);
  1900. end;
  1901. procedure TGLTiledRndLandscape.BoundaryClamp(var x, z: integer);
  1902. begin
  1903. if x < 0 then
  1904. x := 0
  1905. else if x > FExtentX * fLandTileSize then
  1906. x := FExtentX * fLandTileSize;
  1907. if z < 0 then
  1908. z := 0
  1909. else if z > ExtentZ * fLandTileSize then
  1910. z := FExtentZ * fLandTileSize;
  1911. end;
  1912. procedure TGLTiledRndLandscape.CameraPosition(var TileX, TileZ: integer);
  1913. begin
  1914. FindLandTile(-Camera.Position.x, Camera.Position.z, TileX, TileZ);
  1915. end;
  1916. procedure TGLTiledRndLandscape.CleanUp;
  1917. var
  1918. i: integer;
  1919. begin
  1920. for i := fLandTiles.Count - 1 downto 0 do
  1921. begin
  1922. if TGLLandTile(fLandTiles.Items[i]).LandTileInfo.State = hdsNone then
  1923. begin
  1924. fLandTiles.Delete(i); // Free the Landtile and remove it from the list
  1925. // FTerrainRenderer.MaterialLibrary.Materials.DeleteUnusedMaterials;
  1926. end; // if
  1927. end; // for
  1928. end;
  1929. procedure TGLTiledRndLandscape.ComputeLandTile(const aX, aZ: integer; var NewLandTile: TGLLandTile);
  1930. var
  1931. sx, sz: string;
  1932. begin
  1933. FLandTileComputing := True;
  1934. FLandTileInfo.x := aX;
  1935. FLandTileInfo.z := aZ;
  1936. FLandTileInfo.State := hdsPreparing;
  1937. with NewLandTile do
  1938. begin
  1939. Cyclic := False;
  1940. TerrainRenderer := Self.FTerrainRenderer;
  1941. if aX >= 0 then
  1942. sx := 'p'
  1943. else
  1944. sx := 'n';
  1945. if aZ >= 0 then
  1946. sz := 'p'
  1947. else
  1948. sz := 'n';
  1949. Seed := LandTileSeed(aX, aZ);
  1950. Name := Format('Land_%s%d%s%d_', [sx, abs(aX), sz, abs(aZ)]);
  1951. // Generate a unique name
  1952. end; // with
  1953. fComputedLandTile := NewLandTile;
  1954. OnCreateLandTile(aX, aZ, NewLandTile.Seed, NewLandTile);
  1955. with NewLandTile.LandTileInfo do
  1956. FLandTileInfo.State := hdsReady;
  1957. MarkDirty(aX * fLandTileSize, aZ * fLandTileSize, (aX + 1) * fLandTileSize - 1, (aZ + 1) * fLandTileSize - 1);
  1958. fComputedLandTile := nil;
  1959. FLandTileComputing := False;
  1960. fLandTiles.Add(NewLandTile);
  1961. Application.ProcessMessages;
  1962. end;
  1963. procedure TGLTiledRndLandscape.ConstrainCoordinates(var x, z: single);
  1964. begin
  1965. FSingleConstrain(x, z);
  1966. end;
  1967. procedure TGLTiledRndLandscape.ConstrainCoordinates(var x, z: integer);
  1968. begin
  1969. FIntegerConstrain(x, z);
  1970. end;
  1971. constructor TGLTiledRndLandscape.Create(AOwner: TComponent);
  1972. begin
  1973. inherited;
  1974. fLandTiles := tComponentList.Create;
  1975. IsDefaultTile := fDefaultIsDefaultTile;
  1976. OnCreateDefaultTile := fDefaultOnCreateDefaultTile;
  1977. FExtentX := 10000;
  1978. FExtentZ := 10000;
  1979. GenerationRadius := 2;
  1980. FLandTileDensity := 1;
  1981. FLandCover := True;
  1982. end;
  1983. procedure TGLTiledRndLandscape.CyclicClamp(var x, z: integer);
  1984. begin
  1985. exit;
  1986. x := (x + ExtentX) mod ExtentX;
  1987. z := (z + ExtentZ) mod ExtentZ;
  1988. end;
  1989. procedure TGLTiledRndLandscape.CyclicClamp(var x, z: single);
  1990. var
  1991. ix, iz: integer;
  1992. sx, sz: single;
  1993. begin
  1994. exit;
  1995. ix := Trunc(ExtentX + x);
  1996. sx := Frac(x);
  1997. iz := Trunc(ExtentZ + z);
  1998. sz := Frac(z);
  1999. x := (ExtentX * fLandTileSize + ix) mod ExtentX * fLandTileSize + sx;
  2000. z := (ExtentZ * fLandTileSize + iz) mod ExtentZ * fLandTileSize + sz;
  2001. end;
  2002. destructor TGLTiledRndLandscape.Destroy;
  2003. begin
  2004. fLandTiles.Free;
  2005. inherited;
  2006. end;
  2007. function TGLTiledRndLandscape.fDefaultIsDefaultTile(x, z: integer): boolean;
  2008. begin
  2009. InitializeRandomGenerator(LandTileSeed(x, z));
  2010. Result := (random >= FLandTileDensity);
  2011. end;
  2012. procedure TGLTiledRndLandscape.fDefaultOnCreateDefaultTile(heightData: TGLHeightData);
  2013. begin
  2014. heightData.DataState := hdsNone;
  2015. // raise EAccessViolation.Create('No DefaultStartPreparingDefaultTile procedure supplied.');
  2016. end;
  2017. procedure TGLTiledRndLandscape.FindLandTile(const x, z: single; var TileX, TileZ: integer);
  2018. begin
  2019. TileX := Floor(x / fLandTileSize);
  2020. TileZ := Floor(z / fLandTileSize);
  2021. FIntegerConstrain(TileX, TileZ);
  2022. end;
  2023. // Sorting Landscape
  2024. //
  2025. function TGLTiledRndLandscape.fSortLandscapes(Item1, Item2: Pointer): integer;
  2026. var
  2027. x, z: integer;
  2028. d1, d2: single;
  2029. begin
  2030. CameraPosition(x, z);
  2031. d1 := sqr(x - TGLLandTile(Item1^).LandTileInfo.x) + sqr(z - TGLLandTile(Item1^).LandTileInfo.z);
  2032. d2 := sqr(x - TGLLandTile(Item2^).LandTileInfo.x) + sqr(z - TGLLandTile(Item2^).LandTileInfo.z);
  2033. Result := Round(d1 - d2);
  2034. end;
  2035. function TGLTiledRndLandscape.GetTask: string;
  2036. begin
  2037. if fComputedLandTile <> nil then
  2038. Result := fComputedLandTile.Task
  2039. else
  2040. Result := 'Idle';
  2041. end;
  2042. function TGLTiledRndLandscape.GetTaskProgress: integer;
  2043. begin
  2044. if fComputedLandTile <> nil then
  2045. Result := fComputedLandTile.TaskProgress
  2046. else
  2047. Result := 0;
  2048. end;
  2049. procedure TGLTiledRndLandscape.GetTerrainBounds(var l, t, r, b: single);
  2050. begin
  2051. l := 0;
  2052. b := 0;
  2053. t := ExtentZ * LandTileSize;
  2054. r := ExtentX * LandTileSize;
  2055. end;
  2056. procedure TGLTiledRndLandscape.Initialize(const aX, aZ: single);
  2057. var
  2058. cx, cz: integer;
  2059. NewLandTile: TGLLandTile;
  2060. x, z, dx, dz: integer;
  2061. begin
  2062. fOldCamX := -99999;
  2063. fOldCamZ := -99999;
  2064. with Camera.Position do
  2065. begin
  2066. x := aX;
  2067. z := aZ;
  2068. end; // with
  2069. CameraPosition(cx, cz);
  2070. ComputeLandTile(cx, cz, NewLandTile);
  2071. TerrainRenderer.Scale := NewLandTile.Scale;
  2072. with Camera.Position do
  2073. begin
  2074. x := x * NewLandTile.Scale.x;
  2075. z := z * NewLandTile.Scale.z;
  2076. end; // with
  2077. for z := 0 to FGenerationRadius + 1 do
  2078. begin
  2079. for x := 1 to FGenerationRadius + 1 do
  2080. begin
  2081. if Trunc(sqrt(sqr(x) + sqr(z))) <= FGenerationRadius then
  2082. begin
  2083. dx := x;
  2084. dz := z;
  2085. if not IsDefaultTile(cx + dx, cz + dz) then
  2086. ComputeLandTile(cx + dx, cz + dz, NewLandTile);
  2087. dx := -z;
  2088. dz := x;
  2089. if not IsDefaultTile(cx + dx, cz + dz) then
  2090. ComputeLandTile(cx + dx, cz + dz, NewLandTile);
  2091. dx := -x;
  2092. dz := -z;
  2093. if not IsDefaultTile(cx + dx, cz + dz) then
  2094. ComputeLandTile(cx + dx, cz + dz, NewLandTile);
  2095. dx := z;
  2096. dz := -x;
  2097. if not IsDefaultTile(cx + dx, cz + dz) then
  2098. ComputeLandTile(cx + dx, cz + dz, NewLandTile);
  2099. end; // if
  2100. end; // for
  2101. end; // for
  2102. end;
  2103. // Generates a unique seed from the tile coordinates
  2104. //
  2105. function TGLTiledRndLandscape.LandTileSeed(x, z: integer): integer;
  2106. begin
  2107. Result := fBaseSeed + z * ExtentX + x;
  2108. end;
  2109. function TGLTiledRndLandscape.LandtileCount: integer;
  2110. begin
  2111. Result := fLandTiles.Count;
  2112. end;
  2113. // Preparing Land Tile Data
  2114. //
  2115. procedure TGLTiledRndLandscape.PrepareLandTileData(HeightData: TGLHeightData;
  2116. LandTile: TGLLandTile);
  2117. var
  2118. x, y, x0, y0: integer;
  2119. rasterLine: PFloatArray;
  2120. oldType: TGLHeightDataType;
  2121. begin
  2122. with HeightData do
  2123. begin
  2124. DataState := hdsPreparing;
  2125. oldType := DataType;
  2126. Allocate(hdtSingle);
  2127. if XLeft >= 0 then
  2128. x0 := XLeft mod (fLandTileSize)
  2129. else
  2130. x0 := (fLandTileSize + (XLeft mod (fLandTileSize))) mod (fLandTileSize);
  2131. if YTop >= 0 then
  2132. y0 := YTop mod (fLandTileSize)
  2133. else
  2134. y0 := (fLandTileSize + (YTop mod (fLandTileSize))) mod (fLandTileSize);
  2135. MaterialName := Format('%s%d%d',
  2136. [LandTile.Name, x0 div FTerrainRenderer.TileSize,
  2137. y0 div FTerrainRenderer.TileSize]);
  2138. TextureCoordinatesMode := tcmLocal;
  2139. TextureCoordinatesScale := TexPointMake((fLandTileSize) / (Size),
  2140. (fLandTileSize) / (Size));
  2141. for y := y0 to y0 + HeightData.Size - 1 do
  2142. begin
  2143. rasterLine := singleRaster[y - y0];
  2144. for x := x0 to x0 + HeightData.Size - 1 do
  2145. begin
  2146. rasterLine[x - x0] := LandTile.FHeight[x, y];
  2147. end; // for
  2148. end; // for
  2149. DataState := hdsReady;
  2150. if oldType <> hdtSingle then
  2151. DataType := oldType;
  2152. end; // with
  2153. end;
  2154. // Set Camera
  2155. //
  2156. procedure TGLTiledRndLandscape.SetCamera(const Value: TGLCamera);
  2157. begin
  2158. FCamera := Value;
  2159. end;
  2160. procedure TGLTiledRndLandscape.SetCyclic(const Value: boolean);
  2161. begin
  2162. FCyclic := Value;
  2163. if FCyclic then
  2164. begin
  2165. FIntegerConstrain := CyclicClamp;
  2166. FSingleConstrain := CyclicClamp;
  2167. if FTerrainRenderer <> nil then
  2168. FTerrainRenderer.OnGetTerrainBounds := nil;
  2169. end
  2170. else
  2171. begin
  2172. FIntegerConstrain := BoundaryClamp;
  2173. FSingleConstrain := BoundaryClamp;
  2174. if FTerrainRenderer <> nil then
  2175. FTerrainRenderer.OnGetTerrainBounds := GetTerrainBounds;
  2176. end; // else
  2177. end;
  2178. procedure TGLTiledRndLandscape.SetExtentX(const Value: integer);
  2179. begin
  2180. FExtentX := Value;
  2181. FExtentXhalf := FExtentX div 2;
  2182. end;
  2183. procedure TGLTiledRndLandscape.SetExtentZ(const Value: integer);
  2184. begin
  2185. FExtentZ := Value;
  2186. FExtentZhalf := FExtentZ div 2;
  2187. end;
  2188. procedure TGLTiledRndLandscape.SetGenerationRadius(const Value: integer);
  2189. var
  2190. x, z, i: integer;
  2191. begin
  2192. FGenerationRadius := Value;
  2193. SetLength(fGenRadius, sqr(FGenerationRadius * 2 + 1));
  2194. i := 0;
  2195. for z := 0 to FGenerationRadius do
  2196. begin
  2197. for x := 1 to FGenerationRadius do
  2198. begin
  2199. if Trunc(sqrt(sqr(x) + sqr(z))) <= FGenerationRadius then
  2200. begin
  2201. fGenRadius[i].dx := x;
  2202. fGenRadius[i].dz := z;
  2203. fGenRadius[i + 1].dx := -z;
  2204. fGenRadius[i + 1].dz := x;
  2205. fGenRadius[i + 2].dx := -x;
  2206. fGenRadius[i + 2].dz := -z;
  2207. fGenRadius[i + 3].dx := z;
  2208. fGenRadius[i + 3].dz := -x;
  2209. Inc(i, 4);
  2210. end; // if
  2211. end; // for
  2212. end; // for
  2213. SetLength(fGenRadius, i - 3);
  2214. fLandTiles.Capacity := (i - 3) * 2;
  2215. end;
  2216. procedure TGLTiledRndLandscape.SetIsDefaultTile(const Value: TIsDefaultTile);
  2217. begin
  2218. FIsDefaultTile := Value;
  2219. end;
  2220. procedure TGLTiledRndLandscape.SetLandTileCapacity(const Value: integer);
  2221. begin
  2222. FLandTileCapacity := Value;
  2223. end;
  2224. procedure TGLTiledRndLandscape.SetLandTileDensity(const Value: single);
  2225. begin
  2226. FLandTileDensity := Value;
  2227. end;
  2228. procedure TGLTiledRndLandscape.SetOnCreateDefaultTile(const Value: TStartPreparingDataEvent);
  2229. begin
  2230. fOnCreateDefaultTile := Value;
  2231. end;
  2232. procedure TGLTiledRndLandscape.SetOnCreateLandTile(const Value: TOnCreateLandTile);
  2233. begin
  2234. fOnCreateLandTile := Value;
  2235. end;
  2236. procedure TGLTiledRndLandscape.SetSeed(const Value: integer);
  2237. begin
  2238. FSeed := Value;
  2239. InitializeRandomGenerator(FSeed);
  2240. end;
  2241. procedure TGLTiledRndLandscape.SetSize(const aSize: integer);
  2242. begin
  2243. fLandTileSize := aSize;
  2244. end;
  2245. procedure TGLTiledRndLandscape.SetTerrainRenderer(const Value: TGLTerrainRenderer);
  2246. begin
  2247. FTerrainRenderer := Value;
  2248. FTerrainRenderer.HeightDataSource := Self;
  2249. end;
  2250. procedure TGLTiledRndLandscape.StartPreparingData(heightData: TGLHeightData);
  2251. var
  2252. i: integer;
  2253. tx, tz: integer;
  2254. begin
  2255. with heightData do
  2256. begin
  2257. DataState := hdsPreparing;
  2258. if (System.abs(XLeft) mod (heightData.Size - 1) = 0) and (System.abs(YTop) mod (heightData.Size - 1) = 0) then
  2259. begin
  2260. FindLandTile(XLeft, YTop, tx, tz);
  2261. if IsDefaultTile(tx, tz) then
  2262. begin
  2263. OnCreateDefaultTile(heightData);
  2264. exit;
  2265. end; // if
  2266. { Look if the landtile has already been computed }
  2267. for i := 0 to fLandTiles.Count - 1 do
  2268. begin
  2269. with TGLLandTile(fLandTiles.Items[i]).LandTileInfo do
  2270. begin
  2271. if (x = tx) and (z = tz) then
  2272. begin
  2273. if (State = hdsReady) then
  2274. begin
  2275. TGLLandTile(fLandTiles.Items[i]).StartPreparingData(heightData);
  2276. exit;
  2277. end
  2278. else
  2279. break;
  2280. end; // if
  2281. end; // with
  2282. end; // for
  2283. end; // if
  2284. DataState := hdsNone;
  2285. end; // with
  2286. end;
  2287. function TGLTiledRndLandscape.TileDistance(const x1, z1, x2, z2: integer): single;
  2288. begin
  2289. Result := sqrt(sqr(FExtentXhalf - abs(abs(x1 - x2) - FExtentXhalf)) + sqr(FExtentZhalf - abs(abs(z1 - z2) - FExtentZhalf)));
  2290. end;
  2291. function TGLTiledRndLandscape.TileDistanceSquared(const x1, z1, x2, z2: integer): integer;
  2292. begin
  2293. Result := sqr(FExtentXhalf - abs(abs(x1 - x2) - FExtentXhalf)) + sqr(FExtentZhalf - abs(abs(z1 - z2) - FExtentZhalf));
  2294. end;
  2295. procedure TGLTiledRndLandscape.Update;
  2296. var
  2297. i, j, maxi: integer;
  2298. maxd, d: integer;
  2299. cx, cz: integer;
  2300. cx0, cz0: integer;
  2301. Found: boolean;
  2302. NewLandTile: TGLLandTile;
  2303. begin
  2304. CameraPosition(cx0, cz0);
  2305. if fMapUpdating or (fOldCamX = cx0) and (fOldCamZ = cz0) then
  2306. exit;
  2307. for j := 0 to High(fGenRadius) do
  2308. begin
  2309. fMapUpdating := True;
  2310. cx := cx0 + fGenRadius[j].dx;
  2311. cz := cz0 + fGenRadius[j].dz;
  2312. FIntegerConstrain(cx, cz);
  2313. if IsDefaultTile(cx, cz) then
  2314. continue;
  2315. { Look if the landtile has already been computed }
  2316. Found := False;
  2317. for i := 0 to fLandTiles.Count - 1 do
  2318. begin
  2319. with TGLLandTile(fLandTiles.Items[i]).LandTileInfo do
  2320. begin
  2321. if (x = cx) and (z = cz) and (State = hdsReady) then
  2322. begin
  2323. Found := True;
  2324. break;
  2325. end; // if
  2326. end; // with
  2327. end; // for
  2328. { If not, compute it }
  2329. if not Found and not FLandTileComputing then
  2330. begin
  2331. if fLandTiles.Count >= FLandTileCapacity then
  2332. begin // If the tile buffer is full...
  2333. maxd := -1; // ...replace the farthest tile
  2334. maxi := -1;
  2335. for i := 0 to fLandTiles.Count - 1 do
  2336. with TGLLandTile(fLandTiles.Items[i]) do
  2337. begin
  2338. d := sqr(cx0 - LandTileInfo.x) + sqr(cz0 - LandTileInfo.z);
  2339. if d > maxd then
  2340. begin
  2341. maxd := d;
  2342. maxi := i;
  2343. end; // if
  2344. end; // for i
  2345. if sqrt(maxd) > FGenerationRadius + 1 then
  2346. begin
  2347. TGLLandTile(fLandTiles.Items[maxi]).Free;
  2348. end; // if
  2349. end; // if
  2350. ComputeLandTile(cx, cz, NewLandTile);
  2351. fMapUpdating := False;
  2352. exit; // Don't explore further. Let it for the next time step
  2353. end; // if
  2354. end; // for j
  2355. fMapUpdating := False;
  2356. fOldCamX := cx0; // Surrounding completely updated, we can stop checking
  2357. fOldCamZ := cz0;
  2358. fLandTiles.Pack;
  2359. end;
  2360. function TGLTiledRndLandscape.XMoveBoundary: single;
  2361. begin
  2362. Result := ExtentX * LandTileSize * 0.95;
  2363. end;
  2364. function TGLTiledRndLandscape.ZMoveBoundary: single;
  2365. begin
  2366. Result := ExtentZ * LandTileSize * 0.95;
  2367. end;
  2368. //
  2369. // TGLFractalArchipelago
  2370. //
  2371. procedure TGLFractalArchipelago.ComputeLandTile(const aX, aZ: integer; var NewLandTile: TGLLandTile);
  2372. begin
  2373. NewLandTile := TGLFractalHDS.Create(Self);
  2374. NewLandTile.FSlave := True;
  2375. inherited ComputeLandTile(aX, aZ, NewLandTile);
  2376. end;
  2377. constructor TGLFractalArchipelago.Create(AOwner: TComponent);
  2378. begin
  2379. inherited;
  2380. OnCreateLandTile := fOnCreateLandTile;
  2381. IsDefaultTile := FIsDefaultTile;
  2382. IslandDensity := 0.4;
  2383. FWaveAmplitude := 2;
  2384. FWaveSpeed := 20;
  2385. Sea := False; // Sea is drawn by the PostRender event
  2386. end;
  2387. procedure TGLFractalArchipelago.fOnCreateDefaultTile(heightData: TGLHeightData);
  2388. var
  2389. x, y: integer;
  2390. rasterLine: GLS.VectorGeometry.PSingleArray;
  2391. oldType: TGLHeightDataType;
  2392. begin
  2393. with heightData do
  2394. begin
  2395. DataState := hdsPreparing;
  2396. oldType := DataType;
  2397. Allocate(hdtSingle);
  2398. MaterialName := FMaterialName;
  2399. for y := 0 to heightData.Size - 1 do
  2400. begin
  2401. rasterLine := singleRaster[y];
  2402. for x := 0 to heightData.Size - 1 do
  2403. begin
  2404. rasterLine[x] := FSeaLevel;
  2405. end; // for
  2406. end; // for
  2407. if oldType <> hdtSingle then
  2408. DataType := oldType;
  2409. end; // with
  2410. end;
  2411. procedure TGLFractalArchipelago.fOnCreateLandTile(aX, aZ, aSeed: integer; var aLandscape: TGLLandTile);
  2412. begin
  2413. InitializeRandomGenerator(aSeed);
  2414. with TGLFractalHDS(aLandscape) do
  2415. begin
  2416. // Initialize the tile
  2417. Seed := random(MaxInt);
  2418. Depth := Self.fDepth;
  2419. Amplitude := random(FAmplitudeMax - FAmplitudeMin) + FAmplitudeMin;
  2420. Roughness := random * (FRoughnessMax - FRoughnessMin) + FRoughnessMin;
  2421. ApplyLighting(aLandscape);
  2422. ApplyTexture(aLandscape);
  2423. ApplyTopography(aLandscape);
  2424. Cyclic := True;
  2425. PrimerLandscape := True;
  2426. // Generate the landscape
  2427. PrimerIsland(SeaLevel - SeaTransparency, random * Amplitude / 2, FHeight);
  2428. // Pre-generate an island
  2429. BuildHeightField;
  2430. if ErosionByRain.Enabled then
  2431. DoErosionByRain;
  2432. if ErosionByLife.Enabled then
  2433. DoErosionByLife;
  2434. if ErosionBySea.Enabled then
  2435. DoErosionBySea;
  2436. if Sea then
  2437. DoSea;
  2438. BuildNormals;
  2439. if Lighting then
  2440. BuildLightMap
  2441. else
  2442. ClearLightMap;
  2443. BuildTexture;
  2444. FNormal := nil;
  2445. FLightMap := nil;
  2446. end; // with
  2447. end;
  2448. //
  2449. // Code borrowed from Archipelago advanced demo
  2450. //
  2451. procedure TGLFractalArchipelago.FPostRenderSeaDynamic(var rci: TGLRenderContextInfo; var HeightDatas: TList);
  2452. var
  2453. i, x, y, s, s2: integer;
  2454. t: single;
  2455. hd: TGLHeightData;
  2456. const
  2457. r = 0.75;
  2458. g = 0.75;
  2459. b = 1;
  2460. function WaterPhase(const px, py: single): single;
  2461. begin
  2462. Result := t * 1 + px * 0.16 + py * 0.09;
  2463. end;
  2464. procedure IssuePoint(rx, ry: integer);
  2465. var
  2466. px, py: single;
  2467. alpha, colorRatio, ca, sa: single;
  2468. begin
  2469. px := x + rx + s2;
  2470. py := y + ry + s2;
  2471. if hd.DataState = hdsNone then
  2472. begin
  2473. alpha := 1;
  2474. end
  2475. else
  2476. begin
  2477. alpha := (FSeaLevel - hd.SmallIntHeight(rx, ry)) * (1 / FSeaTransparency);
  2478. alpha := ClampValue(alpha, 0.5, 1);
  2479. end;
  2480. SinCos(WaterPhase(px, py) * FWaveSpeed, sa, ca);
  2481. colorRatio := 1 - alpha * 0.1;
  2482. gl.Color4f(r * colorRatio, g * colorRatio, b, alpha);
  2483. gl.TexCoord2f(px * 0.01 + 0.002 * sa, py * 0.01 + 0.0022 * ca - t * 0.01);
  2484. gl.Vertex3f(px, py, FSeaLevel + FWaveAmplitude * sa * VSF);
  2485. end;
  2486. begin
  2487. // if not WaterPlane then Exit;
  2488. t := ((GetTickCount - rhdsStartTime) / 10000);
  2489. FTerrainRenderer.MaterialLibrary.ApplyMaterial(FSeaMaterialName, rci);
  2490. repeat
  2491. // if not WasAboveWater then InverTGLFrontFace;
  2492. gl.PushAttrib(GL_ENABLE_BIT);
  2493. gl.Disable(GL_LIGHTING);
  2494. gl.Disable(GL_NORMALIZE);
  2495. gl.StencilFunc(GL_ALWAYS, 1, 255);
  2496. gl.StencilMask(255);
  2497. gl.StencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
  2498. gl.Enable(GL_STENCIL_TEST);
  2499. gl.Normal3f(0, 0, 1);
  2500. for i := 0 to HeightDatas.Count - 1 do
  2501. begin
  2502. hd := TGLHeightData(HeightDatas.List[i]);
  2503. if (hd.DataState = hdsReady) and (hd.HeightMin > FSeaLevel) then
  2504. continue;
  2505. x := hd.XLeft;
  2506. y := hd.YTop;
  2507. s := hd.Size - 1;
  2508. s2 := s div 2;
  2509. gl.Begin_(GL_TRIANGLE_FAN);
  2510. IssuePoint(s2, s2);
  2511. IssuePoint(0, 0);
  2512. IssuePoint(s2, 0);
  2513. IssuePoint(s, 0);
  2514. IssuePoint(s, s2);
  2515. IssuePoint(s, s);
  2516. IssuePoint(s2, s);
  2517. IssuePoint(0, s);
  2518. IssuePoint(0, s2);
  2519. IssuePoint(0, 0);
  2520. gl.End_;
  2521. end;
  2522. gl.StencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
  2523. gl.PopAttrib;
  2524. // if not WasAboveWater then InverTGLFrontFace;
  2525. // WaterPolyCount:=heightDatas.Count*8;
  2526. until not FTerrainRenderer.MaterialLibrary.UnApplyMaterial(rci);
  2527. end;
  2528. procedure TGLFractalArchipelago.FPostRenderSeaStatic(var rci: TGLRenderContextInfo; var HeightDatas: TList);
  2529. var
  2530. i, x, y, s, s2: integer;
  2531. hd: TGLHeightData;
  2532. t: single;
  2533. const
  2534. r = 0.75;
  2535. g = 0.75;
  2536. b = 1;
  2537. procedure IssuePoint(rx, ry: integer);
  2538. var
  2539. px, py: single;
  2540. alpha, colorRatio: single;
  2541. begin
  2542. px := x + rx + s2;
  2543. py := y + ry + s2;
  2544. if hd.DataState = hdsNone then
  2545. begin
  2546. alpha := 1;
  2547. end
  2548. else
  2549. begin
  2550. alpha := (FSeaLevel - hd.SmallIntHeight(rx, ry)) * (1 / FSeaTransparency);
  2551. alpha := ClampValue(alpha, 0.5, 1);
  2552. end;
  2553. colorRatio := 1 - alpha * 0.1;
  2554. gl.Color4f(r * colorRatio, g * colorRatio, b, alpha);
  2555. gl.TexCoord2f(px * 0.01, py * 0.01 + t);
  2556. gl.Vertex3f(px, py, FSeaLevel);
  2557. end;
  2558. begin
  2559. t := Frac(GetTickCount / 1000);
  2560. FTerrainRenderer.MaterialLibrary.ApplyMaterial(FSeaMaterialName, rci);
  2561. repeat
  2562. // if not WasAboveWater then InverTGLFrontFace;
  2563. gl.PushAttrib(GL_ENABLE_BIT);
  2564. gl.Disable(GL_LIGHTING);
  2565. gl.Disable(GL_NORMALIZE);
  2566. gl.StencilFunc(GL_ALWAYS, 1, 255);
  2567. gl.StencilMask(255);
  2568. gl.StencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
  2569. gl.Enable(GL_STENCIL_TEST);
  2570. gl.Normal3f(0, 0, 1);
  2571. for i := 0 to HeightDatas.Count - 1 do
  2572. begin
  2573. hd := TGLHeightData(HeightDatas.List[i]);
  2574. if (hd.DataState = hdsReady) and (hd.HeightMin > FSeaLevel) then
  2575. continue;
  2576. x := hd.XLeft;
  2577. y := hd.YTop;
  2578. s := hd.Size - 1;
  2579. s2 := s div 2;
  2580. gl.Begin_(GL_TRIANGLE_FAN);
  2581. IssuePoint(s2, s2);
  2582. IssuePoint(0, 0);
  2583. IssuePoint(s2, 0);
  2584. IssuePoint(s, 0);
  2585. IssuePoint(s, s2);
  2586. IssuePoint(s, s);
  2587. IssuePoint(s2, s);
  2588. IssuePoint(0, s);
  2589. IssuePoint(0, s2);
  2590. IssuePoint(0, 0);
  2591. gl.End_;
  2592. end;
  2593. gl.StencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
  2594. gl.PopAttrib;
  2595. // if not WasAboveWater then InverTGLFrontFace;
  2596. // WaterPolyCount := heightDatas.Count*8;
  2597. until not FTerrainRenderer.MaterialLibrary.UnApplyMaterial(rci);
  2598. end;
  2599. function TGLFractalArchipelago.GetIslandDensity: single;
  2600. begin
  2601. Result := FLandTileDensity;
  2602. end;
  2603. procedure TGLFractalArchipelago.SetAmplitudeMax(const Value: integer);
  2604. begin
  2605. FAmplitudeMax := Value;
  2606. end;
  2607. procedure TGLFractalArchipelago.SetAmplitudeMin(const Value: integer);
  2608. begin
  2609. FAmplitudeMin := Value;
  2610. end;
  2611. procedure TGLFractalArchipelago.SetDepth(const Value: integer);
  2612. begin
  2613. fDepth := Value;
  2614. SetSize(Round(IntPower(2, fDepth)));
  2615. end;
  2616. procedure TGLFractalArchipelago.SetIslandDensity(const Value: single);
  2617. begin
  2618. LandTileDensity := Value;
  2619. end;
  2620. procedure TGLFractalArchipelago.SetRoughnessMax(const Value: single);
  2621. begin
  2622. FRoughnessMax := Value;
  2623. end;
  2624. procedure TGLFractalArchipelago.SetRoughnessMin(const Value: single);
  2625. begin
  2626. FRoughnessMin := Value;
  2627. end;
  2628. procedure TGLFractalArchipelago.SetSeaDynamic(const Value: boolean);
  2629. begin
  2630. FSeaDynamic := Value;
  2631. if FSeaDynamic then
  2632. FTerrainRenderer.OnHeightDataPostRender := FPostRenderSeaDynamic
  2633. else
  2634. FTerrainRenderer.OnHeightDataPostRender := FPostRenderSeaStatic;
  2635. end;
  2636. procedure TGLFractalArchipelago.SetSeaMaterialName(const Value: string);
  2637. begin
  2638. FSeaMaterialName := Value;
  2639. end;
  2640. procedure TGLFractalArchipelago.SetTerrainRenderer(const Value: TGLTerrainRenderer);
  2641. begin
  2642. inherited;
  2643. SeaDynamic := FSeaDynamic; // Called to hook the PostRender event handler
  2644. end;
  2645. procedure TGLFractalArchipelago.SetWaveAmplitude(const Value: single);
  2646. begin
  2647. FWaveAmplitude := Value;
  2648. end;
  2649. procedure TGLFractalArchipelago.SetWaveSpeed(const Value: single);
  2650. begin
  2651. FWaveSpeed := Value;
  2652. end;
  2653. (***************************************************************
  2654. ******* RANDOM HDS ALGORITHMS ********
  2655. ***************************************************************)
  2656. procedure FractalMiddlePointHDS(const aDepth, aSeed, aAmplitude: integer;
  2657. const aRoughness: single; aCyclic: boolean;
  2658. var z: TMapOfSingle; var MinZ, MaxZ: single);
  2659. var
  2660. iter, Stp, stp2: integer;
  2661. i, j: integer;
  2662. dz: single;
  2663. Size: integer;
  2664. // Fill variables only if they have not been predefined
  2665. procedure Let(var z: single; const Value: single);
  2666. begin
  2667. if z = Empty then
  2668. z := Value;
  2669. end;
  2670. // Fill variables only if they have not been predefined
  2671. function Get(const x, y: integer; var Value: single): boolean;
  2672. begin
  2673. Value := z[x, y];
  2674. Result := (Value = Empty);
  2675. end;
  2676. function Centre(const x, y, Stp: integer): single;
  2677. begin
  2678. Result := z[x - Stp, y - Stp];
  2679. Result := 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 * 0.25;
  2683. if MinZ > Result then
  2684. MinZ := Result;
  2685. if MaxZ < Result then
  2686. MaxZ := Result;
  2687. end;
  2688. function Side(const x, y, Stp: integer): single;
  2689. var
  2690. n: integer;
  2691. begin
  2692. n := 0;
  2693. Result := 0;
  2694. if y - Stp >= 0 then
  2695. begin
  2696. Result := Result + z[x, y - Stp];
  2697. Inc(n);
  2698. end;
  2699. if y + Stp <= Size then
  2700. begin
  2701. Result := Result + z[x, y + Stp];
  2702. Inc(n);
  2703. end;
  2704. if x - Stp >= 0 then
  2705. begin
  2706. Result := Result + z[x - Stp, y];
  2707. Inc(n);
  2708. end;
  2709. if x + Stp <= Size then
  2710. begin
  2711. Result := Result + z[x + Stp, y];
  2712. Inc(n);
  2713. end;
  2714. Result := Result / n;
  2715. if MinZ > Result then
  2716. MinZ := Result;
  2717. if MaxZ < Result then
  2718. MaxZ := Result;
  2719. end;
  2720. begin
  2721. InitializeRandomGenerator(aSeed);
  2722. Size := High(z);
  2723. dz := aAmplitude * VSF;
  2724. MinZ := 1E38;
  2725. MaxZ := -1E38;
  2726. if aCyclic then
  2727. begin
  2728. Let(z[0, 0], 0);
  2729. Let(z[0, Size], z[0, 0]);
  2730. Let(z[Size, 0], z[0, 0]);
  2731. Let(z[Size, Size], z[0, 0]);
  2732. // Build Height field
  2733. for iter := 1 TO aDepth do
  2734. begin // iterations
  2735. Stp := Round(Size / IntPower(2, (iter - 1))); // step
  2736. stp2 := Stp div 2; // half step
  2737. dz := dz * aRoughness;
  2738. i := stp2;
  2739. repeat
  2740. j := stp2;
  2741. repeat // Centre
  2742. if z[i, j] = Empty then
  2743. begin
  2744. z[i, j] := Centre(i, j, stp2);
  2745. z[i, j] := z[i, j] + (random * dz * 2 - dz) * 1.4;
  2746. end; // if
  2747. Inc(j, Stp);
  2748. until j > Size - stp2 + 1;
  2749. Inc(i, Stp);
  2750. until i > Size - stp2 + 1;
  2751. i := stp2;
  2752. repeat
  2753. j := 0;
  2754. repeat // Sides
  2755. if z[i, j] = Empty then
  2756. begin
  2757. z[i, j] := Side(i, j, stp2);
  2758. z[i, j] := z[i, j] + random * dz * 2 - dz;
  2759. end; // if
  2760. if z[j, i] = Empty then
  2761. begin
  2762. z[j, i] := Side(j, i, stp2);
  2763. z[j, i] := z[j, i] + random * dz * 2 - dz;
  2764. end; // if
  2765. Inc(j, Stp);
  2766. until j >= Size;
  2767. Let(z[Size, i], z[0, i]);
  2768. Let(z[i, Size], z[i, 0]);
  2769. Inc(i, Stp);
  2770. until i > Size - stp2 + 1;
  2771. end; // for iter
  2772. end // if Cyclic
  2773. else
  2774. begin // Non-cyclic landscape
  2775. Let(z[0, 0], random * dz * 2 - dz);
  2776. Let(z[0, Size], random * dz * 2 - dz);
  2777. Let(z[Size, 0], random * dz * 2 - dz);
  2778. Let(z[Size, Size], random * dz * 2 - dz);
  2779. // Build Height field
  2780. for iter := 1 to aDepth do
  2781. begin // iterations
  2782. Stp := Round(Size / IntPower(2, (iter - 1))); // step
  2783. stp2 := Stp div 2; // half step
  2784. dz := dz * aRoughness;
  2785. i := stp2;
  2786. repeat
  2787. j := stp2;
  2788. repeat // Centre
  2789. if z[i, j] = Empty then
  2790. begin
  2791. z[i, j] := Centre(i, j, stp2);
  2792. z[i, j] := z[i, j] + (random * dz * 2 - dz) * 1.4;
  2793. end;
  2794. Inc(j, Stp);
  2795. until j > Size - stp2 + 1;
  2796. Inc(i, Stp);
  2797. until i > Size - stp2 + 1;
  2798. i := stp2;
  2799. repeat
  2800. j := 0;
  2801. repeat // Sides
  2802. if z[i, j] = Empty then
  2803. begin
  2804. z[i, j] := Side(i, j, stp2);
  2805. z[i, j] := z[i, j] + random * dz * 2 - dz;
  2806. end; // if
  2807. if z[j, i] = Empty then
  2808. begin
  2809. z[j, i] := Side(j, i, stp2);
  2810. z[j, i] := z[j, i] + random * dz * 2 - dz;
  2811. end; // if
  2812. Inc(j, Stp);
  2813. until j > Size;
  2814. Inc(i, Stp);
  2815. until i > Size - stp2 + 1;
  2816. end; // for iter
  2817. end; // else Cyclic
  2818. end;
  2819. (***************************************************************
  2820. ******* PREDEFINED HEIGHT-FIELD ********
  2821. ***************************************************************)
  2822. procedure PrimerNull(var z: TMapOfSingle);
  2823. // Empty field
  2824. var
  2825. x, y: integer;
  2826. Size: integer;
  2827. begin
  2828. Size := High(z);
  2829. for y := 0 to Size do
  2830. begin
  2831. for x := 0 to Size do
  2832. begin
  2833. z[x, y] := Empty;
  2834. end; // for
  2835. end; // for
  2836. end;
  2837. (* Ensure that the border of the tile is low (below sea level) and the middle
  2838. is high. *)
  2839. procedure PrimerIsland(LowZ, HighZ: single; var z: TMapOfSingle);
  2840. var
  2841. i: integer;
  2842. Size: integer;
  2843. begin
  2844. Size := High(z);
  2845. PrimerNull(z);
  2846. HighZ := HighZ * VSF;
  2847. LowZ := LowZ * VSF;
  2848. z[Size div 2, Size div 2] := HighZ;
  2849. for i := 0 to Size do
  2850. begin
  2851. z[i, 0] := LowZ;
  2852. z[0, i] := LowZ;
  2853. z[Size, i] := LowZ;
  2854. z[i, Size] := LowZ;
  2855. end; // for i
  2856. end;
  2857. //----------------------------------------------
  2858. initialization
  2859. //----------------------------------------------
  2860. rhdsStartTime := GetTickCount;
  2861. end.