GXS.RandomHDS.pas 91 KB

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