GLS.SkyDome.pas 59 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029
  1. //
  2. // The graphics engine GLScene https://github.com/glscene
  3. //
  4. unit GLS.SkyDome;
  5. (* Skydome classes with celestial grids and routine functions *)
  6. interface
  7. {$I GLS.Scene.inc}
  8. uses
  9. Winapi.OpenGL,
  10. System.Classes,
  11. System.SysUtils,
  12. System.UITypes,
  13. System.Math,
  14. Vcl.Graphics,
  15. GLS.OpenGLTokens,
  16. GLS.VectorTypes,
  17. GLS.VectorGeometry,
  18. GLS.Scene,
  19. GLS.Graphics,
  20. GLS.Color,
  21. GLS.Material,
  22. GLS.RenderContextInfo;
  23. type
  24. TGLStarRecord = packed record
  25. RA : Word; // Right Ascension, x100 builtin factor, degrees
  26. DEC : SmallInt; // Declination, x100 builtin factor, degrees
  27. BVColorIndex : Byte; // ColorIndex, x100 builtin factor
  28. VMagnitude : Byte; // Magnitude, x10 builtin factor
  29. end;
  30. PGLStarRecord = ^TGLStarRecord;
  31. // ------------------------- SkyBox class -------------------------
  32. TGLSkyBoxStyle = (sbsFull, sbsTopHalf, sbsBottomHalf, sbTopTwoThirds, sbsTopHalfClamped);
  33. TGLSkyBox = class(TGLCameraInvariantObject, IGLMaterialLibrarySupported)
  34. private
  35. FMatNameTop: string;
  36. FMatNameRight: string;
  37. FMatNameFront: string;
  38. FMatNameLeft: string;
  39. FMatNameBack: string;
  40. FMatNameBottom: string;
  41. FMatNameClouds: string;
  42. FMaterialLibrary: TGLMaterialLibrary;
  43. FCloudsPlaneOffset: Single;
  44. FCloudsPlaneSize: Single;
  45. FStyle: TGLSkyBoxStyle;
  46. //implementing IGLMaterialLibrarySupported
  47. function GetMaterialLibrary: TGLAbstractMaterialLibrary;
  48. protected
  49. procedure SetMaterialLibrary(const Value: TGLMaterialLibrary);
  50. procedure SetMatNameBack(const Value: string);
  51. procedure SetMatNameBottom(const Value: string);
  52. procedure SetMatNameFront(const Value: string);
  53. procedure SetMatNameLeft(const Value: string);
  54. procedure SetMatNameRight(const Value: string);
  55. procedure SetMatNameTop(const Value: string);
  56. procedure SetMatNameClouds(const Value: string);
  57. procedure SetCloudsPlaneOffset(const Value: single);
  58. procedure SetCloudsPlaneSize(const Value: single);
  59. procedure SetStyle(const value: TGLSkyBoxStyle);
  60. public
  61. constructor Create(AOwner: TComponent); override;
  62. destructor Destroy; override;
  63. procedure DoRender(var ARci: TGLRenderContextInfo;
  64. ARenderSelf, ARenderChildren: Boolean); override;
  65. procedure BuildList(var ARci: TGLRenderContextInfo); override;
  66. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  67. published
  68. property MaterialLibrary: TGLMaterialLibrary read FMaterialLibrary write SetMaterialLibrary;
  69. property MatNameTop: TGLLibMaterialName read FMatNameTop write SetMatNameTop;
  70. property MatNameBottom: TGLLibMaterialName read FMatNameBottom write SetMatNameBottom;
  71. property MatNameLeft: TGLLibMaterialName read FMatNameLeft write SetMatNameLeft;
  72. property MatNameRight: TGLLibMaterialName read FMatNameRight write SetMatNameRight;
  73. property MatNameFront: TGLLibMaterialName read FMatNameFront write SetMatNameFront;
  74. property MatNameBack: TGLLibMaterialName read FMatNameBack write SetMatNameBack;
  75. property MatNameClouds: TGLLibMaterialName read FMatNameClouds write SetMatNameClouds;
  76. property CloudsPlaneOffset: Single read FCloudsPlaneOffset write SetCloudsPlaneOffset;
  77. property CloudsPlaneSize: Single read FCloudsPlaneSize write SetCloudsPlaneSize;
  78. property Style: TGLSkyBoxStyle read FStyle write FStyle default sbsFull;
  79. end;
  80. //--------------------- SkyDome classes -----------------------------
  81. TGLSkyDomeBand = class(TCollectionItem)
  82. private
  83. FStartAngle: Single;
  84. FStopAngle: Single;
  85. FStartColor: TGLColor;
  86. FStopColor: TGLColor;
  87. FSlices: Integer;
  88. FStacks: Integer;
  89. protected
  90. function GetDisplayName: string; override;
  91. procedure SetStartAngle(const val: Single);
  92. procedure SetStartColor(const val: TGLColor);
  93. procedure SetStopAngle(const val: Single);
  94. procedure SetStopColor(const val: TGLColor);
  95. procedure SetSlices(const val: Integer);
  96. procedure SetStacks(const val: Integer);
  97. procedure OnColorChange(sender: TObject);
  98. public
  99. constructor Create(Collection: TCollection); override;
  100. destructor Destroy; override;
  101. procedure Assign(Source: TPersistent); override;
  102. procedure BuildList(var rci: TGLRenderContextInfo);
  103. published
  104. property StartAngle: Single read FStartAngle write SetStartAngle;
  105. property StartColor: TGLColor read FStartColor write SetStartColor;
  106. property StopAngle: Single read FStopAngle write SetStopAngle;
  107. property StopColor: TGLColor read FStopColor write SetStopColor;
  108. property Slices: Integer read FSlices write SetSlices default 12;
  109. property Stacks: Integer read FStacks write SetStacks default 1;
  110. end;
  111. TGLSkyDomeBands = class(TCollection)
  112. protected
  113. owner: TComponent;
  114. function GetOwner: TPersistent; override;
  115. procedure SetItems(index: Integer; const val: TGLSkyDomeBand);
  116. function GetItems(index: Integer): TGLSkyDomeBand;
  117. public
  118. constructor Create(AOwner: TComponent);
  119. function Add: TGLSkyDomeBand;
  120. function FindItemID(ID: Integer): TGLSkyDomeBand;
  121. property Items[index: Integer]: TGLSkyDomeBand read GetItems write SetItems; default;
  122. procedure NotifyChange;
  123. procedure BuildList(var rci: TGLRenderContextInfo);
  124. end;
  125. TGLSkyDomeStar = class(TCollectionItem)
  126. private
  127. FRA, FDec: Single;
  128. FMagnitude: Single;
  129. FColor: TColor;
  130. FCacheCoord: TAffineVector; // cached cartesian coordinates
  131. protected
  132. function GetDisplayName: string; override;
  133. public
  134. constructor Create(Collection: TCollection); override;
  135. destructor Destroy; override;
  136. procedure Assign(Source: TPersistent); override;
  137. published
  138. // Right Ascension, in degrees.
  139. property RA: Single read FRA write FRA;
  140. // Declination, in degrees.
  141. property DEC: Single read FDec write FDec;
  142. // Absolute magnitude.
  143. property Magnitude: Single read FMagnitude write FMagnitude;
  144. // Color of the star.
  145. property Color: TColor read FColor write FColor;
  146. end;
  147. TGLSkyDomeStars = class(TCollection)
  148. protected
  149. owner: TComponent;
  150. function GetOwner: TPersistent; override;
  151. procedure SetItems(index: Integer; const val: TGLSkyDomeStar);
  152. function GetItems(index: Integer): TGLSkyDomeStar;
  153. procedure PrecomputeCartesianCoordinates;
  154. public
  155. constructor Create(AOwner: TComponent);
  156. function Add: TGLSkyDomeStar;
  157. function FindItemID(ID: Integer): TGLSkyDomeStar;
  158. property Items[index: Integer]: TGLSkyDomeStar read GetItems write SetItems; default;
  159. procedure BuildList(var rci: TGLRenderContextInfo; twinkle: Boolean);
  160. (* Adds nb random stars of the given color.
  161. Stars are homogenously scattered on the complete sphere, not only the band defined or visible dome. *)
  162. procedure AddRandomStars(const nb: Integer; const color: TColor; const LimitToTopDome: Boolean = False); overload;
  163. procedure AddRandomStars(const nb: Integer; const ColorMin, ColorMax:TVector3b;
  164. const Magnitude_min, Magnitude_max: Single;
  165. const LimitToTopDome: Boolean = False); overload;
  166. (* Load a 'stars' file, which is made of TGLStarRecord.
  167. Not that '.stars' files should already be sorted by magnitude and color. *)
  168. procedure LoadStarsFile(const starsFileName: string);
  169. end;
  170. TGLSkyDomeOption = (sdoTwinkle);
  171. TGLSkyDomeOptions = set of TGLSkyDomeOption;
  172. (* Renders a sky dome always centered on the camera.
  173. If you use this object make sure it is rendered *first*, as it ignores
  174. depth buffering and overwrites everything. All children of a skydome
  175. are rendered in the skydome's coordinate system.
  176. The skydome is described by "bands", each "band" is an horizontal cut
  177. of a sphere, and you can have as many bands as you wish *)
  178. TGLSkyDome = class(TGLCameraInvariantObject)
  179. private
  180. FOptions: TGLSkyDomeOptions;
  181. FBands: TGLSkyDomeBands;
  182. FStars: TGLSkyDomeStars;
  183. protected
  184. procedure SetBands(const val: TGLSkyDomeBands);
  185. procedure SetStars(const val: TGLSkyDomeStars);
  186. procedure SetOptions(const val: TGLSkyDomeOptions);
  187. public
  188. constructor Create(AOwner: TComponent); override;
  189. destructor Destroy; override;
  190. procedure Assign(Source: TPersistent); override;
  191. procedure BuildList(var rci: TGLRenderContextInfo); override;
  192. published
  193. property Bands: TGLSkyDomeBands read FBands write SetBands;
  194. property Stars: TGLSkyDomeStars read FStars write SetStars;
  195. property Options: TGLSkyDomeOptions read FOptions write SetOptions default [];
  196. end;
  197. TGLEarthSkydomeOption = (esoFadeStarsWithSun, esoRotateOnTwelveHours, esoDepthTest);
  198. TGLEarthSkydomeOptions = set of TGLEarthSkydomeOption;
  199. (* Render a skydome like what can be seen on earth.
  200. Color is based on sun position and turbidity, to "mimic" atmospheric
  201. Rayleigh and Mie scatterings. The colors can be adjusted to render exoplanet atmospheres too.
  202. The default slices/stacks values make for an average quality rendering,
  203. for a very clean rendering, use 64/64 (more is overkill in most cases).
  204. The complexity is quite high though, making a T&L 3D board a necessity
  205. for using TGLEarthSkyDome. *)
  206. TGLEarthSkyDome = class(TGLSkyDome)
  207. private
  208. FSunElevation: Single;
  209. FTurbidity: Single;
  210. FCurSunColor, FCurSkyColor, FCurHazeColor: TGLColorVector;
  211. FCurHazeTurbid, FCurSunSkyTurbid: Single;
  212. FSunZenithColor: TGLColor;
  213. FSunDawnColor: TGLColor;
  214. FHazeColor: TGLColor;
  215. FSkyColor: TGLColor;
  216. FNightColor: TGLColor;
  217. FDeepColor: TGLColor;
  218. FSlices, FStacks: Integer;
  219. FExtendedOptions: TGLEarthSkydomeOptions;
  220. FMorning: Boolean;
  221. protected
  222. procedure Loaded; override;
  223. procedure SetSunElevation(const val: Single);
  224. procedure SetTurbidity(const val: Single);
  225. procedure SetSunZenithColor(const val: TGLColor);
  226. procedure SetSunDawnColor(const val: TGLColor);
  227. procedure SetHazeColor(const val: TGLColor);
  228. procedure SetSkyColor(const val: TGLColor);
  229. procedure SetNightColor(const val: TGLColor);
  230. procedure SetDeepColor(const val: TGLColor);
  231. procedure SetSlices(const val: Integer);
  232. procedure SetStacks(const val: Integer);
  233. procedure OnColorChanged(Sender: TObject);
  234. procedure PreCalculate;
  235. (* Coordinates system note: X is forward, Y is left and Z is up
  236. always rendered as sphere of radius 1 *)
  237. procedure RenderDome;
  238. function CalculateColor(const theta, cosGamma: Single): TGLColorVector;
  239. public
  240. constructor Create(AOwner: TComponent); override;
  241. destructor Destroy; override;
  242. procedure Assign(Source: TPersistent); override;
  243. procedure BuildList(var rci: TGLRenderContextInfo); override;
  244. procedure SetSunAtTime(HH, MM: Single);
  245. published
  246. // Elevation of the sun, measured in degrees
  247. property SunElevation: Single read FSunElevation write SetSunElevation;
  248. // Expresses the purity of air. Value range is from 1 (pure atmosphere) to 120 (very nebulous)
  249. property Turbidity: Single read FTurbidity write SetTurbidity;
  250. property SunZenithColor: TGLColor read FSunZenithColor write SetSunZenithColor;
  251. property SunDawnColor: TGLColor read FSunDawnColor write SetSunDawnColor;
  252. property HazeColor: TGLColor read FHazeColor write SetHazeColor;
  253. property SkyColor: TGLColor read FSkyColor write SetSkyColor;
  254. property NightColor: TGLColor read FNightColor write SetNightColor;
  255. property DeepColor: TGLColor read FDeepColor write SetDeepColor;
  256. property ExtendedOptions: TGLEarthSkydomeOptions read FExtendedOptions write FExtendedOptions;
  257. property Slices: Integer read FSlices write SetSlices default 24;
  258. property Stacks: Integer read FStacks write SetStacks default 48;
  259. end;
  260. type
  261. TGLStarSysData = record
  262. NbStar: byte; // Only 1 allowed so far
  263. NbPlanet: byte;
  264. NbAsteroid: byte;
  265. NbComet: byte;
  266. NbDebris: byte;
  267. end;
  268. TGLStarData = record // Also equal to material texture
  269. (* ONLY .jpg; Expected: .bmp .tif .tga .png ignored *)
  270. StarName: String[255];
  271. Radius: Double;
  272. ObjectRotation: Double;
  273. AxisTilt: Double;
  274. nbS3ds: byte;
  275. DocIndex: byte;
  276. StarSysScale: Double;
  277. StarDistanceScale: Double;
  278. end;
  279. TGLPlanetData = record
  280. // Planet.jpg .. Planet_bump.jpg
  281. Name: String[255];
  282. Radius: Double;
  283. ObjectRotation: Double;
  284. AxisTilt: Double;
  285. nbRings: byte;
  286. nbMoons: byte;
  287. nbS3ds: byte;
  288. DocIndex: byte;
  289. Albedo, OrbitRotation: Double;
  290. aDistance, aDistanceVar: Double; // aConstEdit aVarEdit
  291. Inclination, InclinationVar: Double; // iConstEdit iVarEdit
  292. Eccentricity, EVar, EMax: Double; // eConstEdit eVarEdit EMaxEdit
  293. nLongitude, nLongitudeVar: Double; // NConstEdit NVarEdit
  294. wPerihelion, wPerihelionVar: Double; // wConstEdit wVarEdit
  295. mAnomaly, mAnomalyVar: Double; // MConstEdit MVarEdit
  296. Mass, Density: Double;
  297. Atmosphere, VelocityType: byte;
  298. (* Which way does the wind blow Given a direction
  299. 0 to 100 or 1 to 100 is that 100 or 101 *)
  300. Velocity, VelocityDir: Double;
  301. end;
  302. TGLMoonRingData = record // 3ds files and DebrisAsteroid too
  303. Name: String[255]; // Planet_Moon.jpg
  304. Radius: Double;
  305. ObjectRotation: Double;
  306. AxisTilt: Double;
  307. S3dsTex: Boolean;
  308. DocIndex: byte;
  309. Mass, Density: Double;
  310. RCDType, RCDCount: Integer;
  311. RCDXYSize, RCDZSize, RCDPosition: Double;
  312. Albedo, OrbitRotation: Double;
  313. aDistance, aDistanceVar: Double;
  314. Inclination, InclinationVar: Double;
  315. Eccentricity, EVar, EMax: Double;
  316. nLongitude, nLongitudeVar: Double;
  317. wPerihelion, wPerihelionVar: Double;
  318. mAnomaly, mAnomalyVar: Double;
  319. Atmosphere, VelocityType: byte;
  320. Velocity, VelocityDir: Double;
  321. end;
  322. TGLAsteroidData = record // Asteroid Comet spheres..NOT DebrisAsteroid
  323. Name: String[255];
  324. Radius: Double;
  325. ObjectRotation: Double;
  326. AxisTilt: Double;
  327. nbS3ds: byte;
  328. DocIndex: byte;
  329. RCDType, RCDCount: Integer;
  330. RCDXYSize, RCDZSize, RCDPosition: Double;
  331. Albedo, OrbitRotation: Double;
  332. aDistance, aDistanceVar: Double;
  333. Inclination, InclinationVar: Double;
  334. Eccentricity, EVar, EMax: Double;
  335. nLongitude, nLongitudeVar: Double;
  336. wPerihelion, wPerihelionVar: Double;
  337. mAnomaly, mAnomalyVar: Double;
  338. Mass, Density: Double;
  339. Atmosphere, VelocityType: byte;
  340. Velocity, VelocityDir: Double;
  341. end;
  342. // For recomputation of TOrbitalElementsData
  343. TOrbitalElements = record
  344. N: Double; // longitude of the ascending node
  345. i: Double; // inclination to the ecliptic (plane of the Earth's orbit)
  346. w: Double; // argument of perihelion
  347. a: Double; // semi-major axis, or mean distance from Sun
  348. e: Double; // eccentricity (0=circle, 0-1=ellipse, 1=parabola)
  349. M: Double; // mean anomaly (0 at perihelion; increases uniformly with time)
  350. end;
  351. TOrbitalElementsData = record
  352. NConst, NVar: Double; // longitude of the ascending node
  353. iConst, iVar: Double; // inclination to the ecliptic (plane of the Earth's orbit)
  354. wConst, wVar: Double; // argument of perihelion
  355. aConst, aVar: Double; // semi-major axis, or mean distance from Sun
  356. eConst, eVar: Double; // eccentricity (0=circle, 0-1=ellipse, 1=parabola)
  357. MConst, MVar: Double; // mean anomaly (0 at perihelion; increases uniformly with time)
  358. end;
  359. const
  360. // geocentric sun elements
  361. cSunOrbitalElements: TOrbitalElementsData = (NConst: 0.0; NVar: 0.0;
  362. iConst: 0.0; iVar: 0.0; wConst: 282.9404; wVar: 4.70935E-5;
  363. aConst: 1.000000; aVar: 0.0; // (AU)
  364. eConst: 0.016709; eVar: - 1.151E-9; MConst: 356.0470; MVar: 0.9856002585);
  365. // geocentric moon elements
  366. cMoonOrbitalElements: TOrbitalElementsData = (NConst: 125.1228;
  367. NVar: - 0.0529538083; iConst: 5.1454; iVar: 0.0; wConst: 318.0634;
  368. wVar: 0.1643573223; aConst: 60.2666; aVar: 0.0; // (Earth radii)
  369. eConst: 0.054900; eVar: 0.0; MConst: 115.3654; MVar: 13.0649929509);
  370. // heliocentric mercury elements
  371. cMercuryOrbitalElements: TOrbitalElementsData = (NConst: 48.3313;
  372. NVar: 3.24587E-5; iConst: 7.0047; iVar: 5.00E-8; wConst: 29.1241;
  373. wVar: 1.01444E-5; aConst: 0.387098; aVar: 0.0; // (AU)
  374. eConst: 0.205635; eVar: 5.59E-10; MConst: 168.6562; MVar: 4.0923344368);
  375. // heliocentric venus elements
  376. cVenusOrbitalElements: TOrbitalElementsData = (NConst: 76.6799;
  377. NVar: 2.46590E-5; iConst: 3.3946; iVar: 2.75E-8; wConst: 54.8910;
  378. wVar: 1.38374E-5; aConst: 0.723330; aVar: 0.0; // (AU)
  379. eConst: 0.006773; eVar: - 1.302E-9; MConst: 48.0052; MVar: 1.6021302244);
  380. // heliocentric mars elements
  381. cMarsOrbitalElements: TOrbitalElementsData = (NConst: 49.5574;
  382. NVar: 2.11081E-5; iConst: 1.8497; iVar: - 1.78E-8; wConst: 286.5016;
  383. wVar: 2.92961E-5; aConst: 1.523688; aVar: 0.0; // (AU)
  384. eConst: 0.093405; eVar: 2.516E-9; MConst: 18.6021; MVar: 0.5240207766);
  385. // heliocentric jupiter elements
  386. cJupiterOrbitalElements: TOrbitalElementsData = (NConst: 100.4542;
  387. NVar: 2.76854E-5; iConst: 1.3030; iVar: - 1.557E-7; wConst: 273.8777;
  388. wVar: 1.64505E-5; aConst: 5.20256; aVar: 0.0; // (AU)
  389. eConst: 0.048498; eVar: 4.469E-9; MConst: 19.8950; MVar: 0.0830853001);
  390. // heliocentric saturn elements
  391. cSaturnOrbitalElements: TOrbitalElementsData = (NConst: 113.6634;
  392. NVar: 2.38980E-5; iConst: 2.4886; iVar: - 1.081E-7; wConst: 339.3939;
  393. wVar: 2.97661E-5; aConst: 9.55475; aVar: 0.0; // (AU)
  394. eConst: 0.055546; eVar: - 9.499E-9; MConst: 316.9670; MVar: 0.0334442282);
  395. // heliocentric uranus elements
  396. cUranusOrbitalElements: TOrbitalElementsData = (NConst: 74.0005;
  397. NVar: 1.3978E-5; iConst: 0.7733; iVar: 1.9E-8; wConst: 96.6612;
  398. wVar: 3.0565E-5; aConst: 19.18171; aVar: - 1.55E-8; // (AU)
  399. eConst: 0.047318; eVar: 7.45E-9; MConst: 142.5905; MVar: 0.011725806);
  400. // heliocentric neptune elements
  401. cNeptuneOrbitalElements: TOrbitalElementsData = (NConst: 131.7806;
  402. NVar: 3.0173E-5; iConst: 1.7700; iVar: - 2.55E-7; wConst: 272.8461;
  403. wVar: - 6.027E-6; aConst: 30.05826; aVar: 3.313E-8; // (AU)
  404. eConst: 0.008606; eVar: 2.15E-9; MConst: 260.2471; MVar: 0.005995147);
  405. // heliocentric pluto elements
  406. cPlutoOrbitalElements: TOrbitalElementsData = (NConst: 162.7806;
  407. NVar: 3.0173E-5; iConst: 1.7700; iVar: - 2.55E-7; wConst: 272.8461;
  408. wVar: - 6.027E-6; aConst: 30.05826; aVar: 3.313E-8; // (AU)
  409. eConst: 0.008606; EVar: 2.15E-9; MConst: 260.2471; MVar: 0.005995147);
  410. cAUToKilometers = 149.6E6; // astronomical units to kilometers
  411. cEarthRadius = 6371; // average earth radius in kilometers
  412. // Converts a TDateTime (GMT+0) into the Julian day used for computations.
  413. function GMTDateTimeToJulianDay(const dt: TDateTime): Double;
  414. // Compute orbital elements for given Julian day.
  415. function ComputeOrbitalElements(const oeData: TOrbitalElementsData;
  416. const d: Double): TOrbitalElements;
  417. // Compute the planet position for given Julian day (in AU).
  418. function ComputePlanetPosition(const orbitalElements: TOrbitalElements)
  419. : TAffineVector; overload;
  420. function ComputePlanetPosition(const orbitalElementsData: TOrbitalElementsData;
  421. const d: Double): TAffineVector; overload;
  422. // Computes position on the unit sphere of a star record (Z=up)
  423. function StarRecordPositionZUp(const starRecord: TGLStarRecord): TAffineVector;
  424. // Computes position on the unit sphere of a star record (Y=up)
  425. function StarRecordPositionYUp(const starRecord: TGLStarRecord): TAffineVector;
  426. // Computes position on the unit sphere of a star using Longitude and Latitude
  427. function LonLatToPos(Lon, Lat: Single): TAffineVector;
  428. // Computes star color from BV index (RGB) and magnitude (alpha)
  429. function StarRecordColor(const starRecord: TGLStarRecord; bias: Single): TVector4f;
  430. //----------------------------------------------------------------------
  431. implementation
  432. //----------------------------------------------------------------------
  433. uses
  434. GLS.Context,
  435. GLS.State;
  436. //--------------------------- Functions --------------------------------
  437. function GMTDateTimeToJulianDay(const dt: TDateTime): Double;
  438. begin
  439. Result := dt - EncodeDate(2000, 1, 1);
  440. end;
  441. //--------------------------------------------------------------------------------
  442. function ComputeOrbitalElements(const oeData: TOrbitalElementsData;
  443. const d: Double): TOrbitalElements;
  444. begin
  445. with Result, oeData do
  446. begin
  447. N := NConst + NVar * d;
  448. i := iConst + iVar * d;
  449. w := wConst + wVar * d;
  450. a := aConst + aVar * d;
  451. e := eConst + eVar * d;
  452. M := MConst + MVar * d;
  453. end;
  454. end;
  455. //--------------------------------------------------------------------------------
  456. function ComputePlanetPosition(const orbitalElements: TOrbitalElements)
  457. : TAffineVector;
  458. var
  459. eccentricAnomaly, eA0: Double;
  460. sm, cm, se, ce, si, ci, cn, sn, cvw, svw: Double;
  461. xv, yv, v, r: Double;
  462. nn: Integer; // numerical instability bailout
  463. begin
  464. with orbitalElements do
  465. begin
  466. // E = M + e*(180/pi) * sin(M) * ( 1.0 + e * cos(M) )
  467. SinCos(M * cPIdiv180, sm, cm);
  468. eccentricAnomaly := M + e * c180divPI * sm * (1.0 + e * cm);
  469. nn := 0;
  470. repeat
  471. eA0 := eccentricAnomaly;
  472. // E1 = E0 - ( E0 - e*(180/pi) * sin(E0) - M ) / ( 1 - e * cos(E0) )
  473. SinCos(eA0 * cPIdiv180, se, ce);
  474. eccentricAnomaly := eA0 - (eA0 - e * c180divPI * se - M) / (1 - e * ce);
  475. Inc(nn);
  476. until (nn > 10) or (Abs(eccentricAnomaly - eA0) < 1E-4);
  477. SinCos(eccentricAnomaly * cPIdiv180, se, ce);
  478. xv := a * (ce - e);
  479. yv := a * (Sqrt(1.0 - e * e) * se);
  480. v := ArcTan2(yv, xv) * c180divPI;
  481. r := Sqrt(xv * xv + yv * yv);
  482. SinCos(i * cPIdiv180, si, ci);
  483. SinCos(N * cPIdiv180, sn, cn);
  484. SinCos((v + w) * cPIdiv180, svw, cvw);
  485. end;
  486. // xh = r * ( cos(N) * cos(v+w) - sin(N) * sin(v+w) * cos(i) )
  487. Result.X := r * (cn * cvw - sn * svw * ci);
  488. // yh = r * ( sin(N) * cos(v+w) + cos(N) * sin(v+w) * cos(i) )
  489. Result.Y := r * (sn * cvw + cn * svw * ci);
  490. // zh = r * ( sin(v+w) * sin(i) )
  491. Result.Z := r * (svw * si);
  492. end;
  493. //--------------------------------------------------------------------------------
  494. function ComputePlanetPosition(const orbitalElementsData: TOrbitalElementsData;
  495. const d: Double): TAffineVector;
  496. var
  497. oe: TOrbitalElements;
  498. begin
  499. oe := ComputeOrbitalElements(orbitalElementsData, d);
  500. Result := ComputePlanetPosition(oe);
  501. end;
  502. //----------------------------------------------------------------------
  503. function StarRecordPositionYUp(const starRecord: TGLStarRecord): TAffineVector;
  504. var
  505. f: Single;
  506. begin
  507. SinCosine(starRecord.DEC * (0.01 * PI / 180), Result.Y, f);
  508. SinCosine(starRecord.RA * (0.01 * PI / 180), f, Result.X, Result.Z);
  509. end;
  510. //----------------------------------------------------------------------
  511. function StarRecordPositionZUp(const starRecord: TGLStarRecord): TAffineVector;
  512. var
  513. f: Single;
  514. begin
  515. SinCosine(starRecord.DEC * (0.01 * PI / 180), Result.Z, f);
  516. SinCosine(starRecord.RA * (0.01 * PI / 180), f, Result.X, Result.Y);
  517. end;
  518. //----------------------------------------------------------------------
  519. function LonLatToPos(Lon, Lat: Single): TAffineVector;
  520. var
  521. f: Single;
  522. begin
  523. SinCosine(Lat * (PI / 180), Result.Y, f);
  524. SinCosine(Lon * (360 / 24 * PI / 180), f, Result.X, Result.Z);
  525. end;
  526. //----------------------------------------------------------------------
  527. function StarRecordColor(const starRecord: TGLStarRecord; bias: Single): TVector4f;
  528. const
  529. // very *rough* approximation
  530. cBVm035: TVector4f = (X: 0.7; Y: 0.8; Z: 1.0; W: 1);
  531. cBV015: TVector4f = (X: 1.0; Y: 1.0; Z: 1.0; W: 1);
  532. cBV060: TVector4f = (X: 1.0; Y: 1.0; Z: 0.7; W: 1);
  533. cBV135: TVector4f = (X: 1.0; Y: 0.8; Z: 0.7; W: 1);
  534. var
  535. bvIndex100: Integer;
  536. begin
  537. bvIndex100 := starRecord.BVColorIndex - 50;
  538. // compute RGB color for B&V index
  539. if bvIndex100 < -035 then
  540. Result := cBVm035
  541. else if bvIndex100 < 015 then
  542. VectorLerp(cBVm035, cBV015, (bvIndex100 + 035) * (1 / (015 + 035)), Result)
  543. else if bvIndex100 < 060 then
  544. VectorLerp(cBV015, cBV060, (bvIndex100 - 015) * (1 / (060 - 015)), Result)
  545. else if bvIndex100 < 135 then
  546. VectorLerp(cBV060, cBV135, (bvIndex100 - 060) * (1 / (135 - 060)), Result)
  547. else
  548. Result := cBV135;
  549. // compute transparency for VMag
  550. // the actual factor is 2.512, and not used here
  551. Result.W := PowerSingle(1.2, -(starRecord.VMagnitude * 0.1 - bias));
  552. end;
  553. // ------------------
  554. // ------------------ TGLSkyBox ------------------
  555. // ------------------
  556. constructor TGLSkyBox.Create(AOwner: TComponent);
  557. begin
  558. inherited Create(AOwner);
  559. CamInvarianceMode := cimPosition;
  560. ObjectStyle := ObjectStyle + [osDirectDraw, osNoVisibilityCulling];
  561. FCloudsPlaneOffset := 0.2;
  562. // this should be set far enough to avoid near plane clipping
  563. FCloudsPlaneSize := 32;
  564. // the bigger, the more this extends the clouds cap to the horizon
  565. end;
  566. destructor TGLSkyBox.Destroy;
  567. begin
  568. inherited;
  569. end;
  570. function TGLSkyBox.GetMaterialLibrary: TGLAbstractMaterialLibrary;
  571. begin
  572. Result := FMaterialLibrary;
  573. end;
  574. procedure TGLSkyBox.Notification(AComponent: TComponent; Operation: TOperation);
  575. begin
  576. if (Operation = opRemove) and (AComponent = FMaterialLibrary) then
  577. MaterialLibrary := nil;
  578. inherited;
  579. end;
  580. procedure TGLSkyBox.DoRender(var ARci: TGLRenderContextInfo; ARenderSelf,
  581. ARenderChildren: Boolean);
  582. begin
  583. // We want children of the sky box to appear far away too
  584. // (note: simply not writing to depth buffer may not make this not work,
  585. // child objects may need the depth buffer to render themselves properly,
  586. // this may require depth buffer cleared after that. - DanB)
  587. Arci.GLStates.DepthWriteMask := False;
  588. Arci.ignoreDepthRequests := true;
  589. inherited;
  590. Arci.ignoreDepthRequests := False;
  591. end;
  592. procedure TGLSkyBox.BuildList(var ARci: TGLRenderContextInfo);
  593. var
  594. f, cps, cof1: Single;
  595. oldStates: TGLStates;
  596. libMat: TGLLibMaterial;
  597. begin
  598. if FMaterialLibrary = nil then
  599. Exit;
  600. with ARci.GLStates do
  601. begin
  602. oldStates := States;
  603. Disable(stDepthTest);
  604. Disable(stLighting);
  605. Disable(stFog);
  606. end;
  607. gl.PushMatrix;
  608. f := ARci.rcci.farClippingDistance * 0.5;
  609. gl.Scalef(f, f, f);
  610. try
  611. case Style of
  612. sbsFull: ;
  613. sbsTopHalf, sbsTopHalfClamped:
  614. begin
  615. gl.Translatef(0, 0.5, 0);
  616. gl.Scalef(1, 0.5, 1);
  617. end;
  618. sbsBottomHalf:
  619. begin
  620. gl.Translatef(0, -0.5, 0);
  621. gl.Scalef(1, 0.5, 1);
  622. end;
  623. sbTopTwoThirds:
  624. begin
  625. gl.Translatef(0, 1 / 3, 0);
  626. gl.Scalef(1, 2 / 3, 1);
  627. end;
  628. end;
  629. // FRONT
  630. libMat := MaterialLibrary.LibMaterialByName(FMatNameFront);
  631. if libMat <> nil then
  632. begin
  633. libMat.Apply(ARci);
  634. repeat
  635. gl.Begin_(GL_QUADS);
  636. xgl.TexCoord2f(0.002, 0.998);
  637. gl.Vertex3f(-1, 1, -1);
  638. xgl.TexCoord2f(0.002, 0.002);
  639. gl.Vertex3f(-1, -1, -1);
  640. xgl.TexCoord2f(0.998, 0.002);
  641. gl.Vertex3f(1, -1, -1);
  642. xgl.TexCoord2f(0.998, 0.998);
  643. gl.Vertex3f(1, 1, -1);
  644. if Style = sbsTopHalfClamped then
  645. begin
  646. xgl.TexCoord2f(0.002, 0.002);
  647. gl.Vertex3f(-1, -1, -1);
  648. xgl.TexCoord2f(0.002, 0.002);
  649. gl.Vertex3f(-1, -3, -1);
  650. xgl.TexCoord2f(0.998, 0.002);
  651. gl.Vertex3f(1, -3, -1);
  652. xgl.TexCoord2f(0.998, 0.002);
  653. gl.Vertex3f(1, -1, -1);
  654. end;
  655. gl.End_;
  656. until not libMat.UnApply(ARci);
  657. end;
  658. // BACK
  659. libMat := MaterialLibrary.LibMaterialByName(FMatNameBack);
  660. if libMat <> nil then
  661. begin
  662. libMat.Apply(ARci);
  663. repeat
  664. gl.Begin_(GL_QUADS);
  665. xgl.TexCoord2f(0.002, 0.998);
  666. gl.Vertex3f(1, 1, 1);
  667. xgl.TexCoord2f(0.002, 0.002);
  668. gl.Vertex3f(1, -1, 1);
  669. xgl.TexCoord2f(0.998, 0.002);
  670. gl.Vertex3f(-1, -1, 1);
  671. xgl.TexCoord2f(0.998, 0.998);
  672. gl.Vertex3f(-1, 1, 1);
  673. if Style = sbsTopHalfClamped then
  674. begin
  675. xgl.TexCoord2f(0.002, 0.002);
  676. gl.Vertex3f(1, -1, 1);
  677. xgl.TexCoord2f(0.002, 0.002);
  678. gl.Vertex3f(1, -3, 1);
  679. xgl.TexCoord2f(0.998, 0.002);
  680. gl.Vertex3f(-1, -3, 1);
  681. xgl.TexCoord2f(0.998, 0.002);
  682. gl.Vertex3f(-1, -1, 1);
  683. end;
  684. gl.End_;
  685. until not libMat.UnApply(ARci);
  686. end;
  687. // TOP
  688. libMat := MaterialLibrary.LibMaterialByName(FMatNameTop);
  689. if libMat <> nil then
  690. begin
  691. libMat.Apply(ARci);
  692. repeat
  693. gl.Begin_(GL_QUADS);
  694. xgl.TexCoord2f(0.002, 0.998);
  695. gl.Vertex3f(-1, 1, 1);
  696. xgl.TexCoord2f(0.002, 0.002);
  697. gl.Vertex3f(-1, 1, -1);
  698. xgl.TexCoord2f(0.998, 0.002);
  699. gl.Vertex3f(1, 1, -1);
  700. xgl.TexCoord2f(0.998, 0.998);
  701. gl.Vertex3f(1, 1, 1);
  702. gl.End_;
  703. until not libMat.UnApply(ARci);
  704. end;
  705. // BOTTOM
  706. libMat := MaterialLibrary.LibMaterialByName(FMatNameBottom);
  707. if libMat <> nil then
  708. begin
  709. libMat.Apply(ARci);
  710. repeat
  711. gl.Begin_(GL_QUADS);
  712. xgl.TexCoord2f(0.002, 0.998);
  713. gl.Vertex3f(-1, -1, -1);
  714. xgl.TexCoord2f(0.002, 0.002);
  715. gl.Vertex3f(-1, -1, 1);
  716. xgl.TexCoord2f(0.998, 0.002);
  717. gl.Vertex3f(1, -1, 1);
  718. xgl.TexCoord2f(0.998, 0.998);
  719. gl.Vertex3f(1, -1, -1);
  720. gl.End_;
  721. until not libMat.UnApply(ARci);
  722. end;
  723. // LEFT
  724. libMat := MaterialLibrary.LibMaterialByName(FMatNameLeft);
  725. if libMat <> nil then
  726. begin
  727. libMat.Apply(ARci);
  728. repeat
  729. gl.Begin_(GL_QUADS);
  730. xgl.TexCoord2f(0.002, 0.998);
  731. gl.Vertex3f(-1, 1, 1);
  732. xgl.TexCoord2f(0.002, 0.002);
  733. gl.Vertex3f(-1, -1, 1);
  734. xgl.TexCoord2f(0.998, 0.002);
  735. gl.Vertex3f(-1, -1, -1);
  736. xgl.TexCoord2f(0.998, 0.998);
  737. gl.Vertex3f(-1, 1, -1);
  738. if Style = sbsTopHalfClamped then
  739. begin
  740. xgl.TexCoord2f(0.002, 0.002);
  741. gl.Vertex3f(-1, -1, 1);
  742. xgl.TexCoord2f(0.002, 0.002);
  743. gl.Vertex3f(-1, -3, 1);
  744. xgl.TexCoord2f(0.998, 0.002);
  745. gl.Vertex3f(-1, -3, -1);
  746. xgl.TexCoord2f(0.998, 0.002);
  747. gl.Vertex3f(-1, -1, -1);
  748. end;
  749. gl.End_;
  750. until not libMat.UnApply(ARci);
  751. end;
  752. // RIGHT
  753. libMat := MaterialLibrary.LibMaterialByName(FMatNameRight);
  754. if libMat <> nil then
  755. begin
  756. libMat.Apply(ARci);
  757. repeat
  758. gl.Begin_(GL_QUADS);
  759. xgl.TexCoord2f(0.002, 0.998);
  760. gl.Vertex3f(1, 1, -1);
  761. xgl.TexCoord2f(0.002, 0.002);
  762. gl.Vertex3f(1, -1, -1);
  763. xgl.TexCoord2f(0.998, 0.002);
  764. gl.Vertex3f(1, -1, 1);
  765. xgl.TexCoord2f(0.998, 0.998);
  766. gl.Vertex3f(1, 1, 1);
  767. if Style = sbsTopHalfClamped then
  768. begin
  769. xgl.TexCoord2f(0.002, 0.002);
  770. gl.Vertex3f(1, -1, -1);
  771. xgl.TexCoord2f(0.002, 0.002);
  772. gl.Vertex3f(1, -3, -1);
  773. xgl.TexCoord2f(0.998, 0.002);
  774. gl.Vertex3f(1, -3, 1);
  775. xgl.TexCoord2f(0.998, 0.002);
  776. gl.Vertex3f(1, -1, 1);
  777. end;
  778. gl.End_;
  779. until not libMat.UnApply(ARci);
  780. end;
  781. // CLOUDS CAP PLANE
  782. libMat := MaterialLibrary.LibMaterialByName(FMatNameClouds);
  783. if libMat <> nil then
  784. begin
  785. // pre-calculate possible values to speed up
  786. cps := FCloudsPlaneSize * 0.5;
  787. cof1 := FCloudsPlaneOffset;
  788. libMat.Apply(ARci);
  789. repeat
  790. gl.Begin_(GL_QUADS);
  791. xgl.TexCoord2f(0, 1);
  792. gl.Vertex3f(-cps, cof1, cps);
  793. xgl.TexCoord2f(0, 0);
  794. gl.Vertex3f(-cps, cof1, -cps);
  795. xgl.TexCoord2f(1, 0);
  796. gl.Vertex3f(cps, cof1, -cps);
  797. xgl.TexCoord2f(1, 1);
  798. gl.Vertex3f(cps, cof1, cps);
  799. gl.End_;
  800. until not libMat.UnApply(ARci);
  801. end;
  802. gl.PopMatrix;
  803. if stLighting in oldStates then
  804. ARci.GLStates.Enable(stLighting);
  805. if stFog in oldStates then
  806. ARci.GLStates.Enable(stFog);
  807. if stDepthTest in oldStates then
  808. ARci.GLStates.Enable(stDepthTest);
  809. finally
  810. end;
  811. end;
  812. procedure TGLSkyBox.SetCloudsPlaneOffset(const Value: single);
  813. begin
  814. FCloudsPlaneOffset := Value;
  815. StructureChanged;
  816. end;
  817. procedure TGLSkyBox.SetCloudsPlaneSize(const Value: single);
  818. begin
  819. FCloudsPlaneSize := Value;
  820. StructureChanged;
  821. end;
  822. procedure TGLSkyBox.SetStyle(const value: TGLSkyBoxStyle);
  823. begin
  824. FStyle := value;
  825. StructureChanged;
  826. end;
  827. procedure TGLSkyBox.SetMaterialLibrary(const value: TGLMaterialLibrary);
  828. begin
  829. FMaterialLibrary := value;
  830. StructureChanged;
  831. end;
  832. procedure TGLSkyBox.SetMatNameBack(const Value: string);
  833. begin
  834. FMatNameBack := Value;
  835. StructureChanged;
  836. end;
  837. procedure TGLSkyBox.SetMatNameBottom(const Value: string);
  838. begin
  839. FMatNameBottom := Value;
  840. StructureChanged;
  841. end;
  842. procedure TGLSkyBox.SetMatNameClouds(const Value: string);
  843. begin
  844. FMatNameClouds := Value;
  845. StructureChanged;
  846. end;
  847. procedure TGLSkyBox.SetMatNameFront(const Value: string);
  848. begin
  849. FMatNameFront := Value;
  850. StructureChanged;
  851. end;
  852. procedure TGLSkyBox.SetMatNameLeft(const Value: string);
  853. begin
  854. FMatNameLeft := Value;
  855. StructureChanged;
  856. end;
  857. procedure TGLSkyBox.SetMatNameRight(const Value: string);
  858. begin
  859. FMatNameRight := Value;
  860. StructureChanged;
  861. end;
  862. procedure TGLSkyBox.SetMatNameTop(const Value: string);
  863. begin
  864. FMatNameTop := Value;
  865. StructureChanged;
  866. end;
  867. //--------------------- SkyDome Region ------------------------------
  868. // ------------------
  869. // ------------------ TGLSkyDomeBand ------------------
  870. // ------------------
  871. constructor TGLSkyDomeBand.Create(Collection: TCollection);
  872. begin
  873. inherited Create(Collection);
  874. FStartColor := TGLColor.Create(Self);
  875. FStartColor.Initialize(clrBlue);
  876. FStartColor.OnNotifyChange := OnColorChange;
  877. FStopColor := TGLColor.Create(Self);
  878. FStopColor.Initialize(clrBlue);
  879. FStopColor.OnNotifyChange := OnColorChange;
  880. FSlices := 12;
  881. FStacks := 1;
  882. end;
  883. destructor TGLSkyDomeBand.Destroy;
  884. begin
  885. FStartColor.Free;
  886. FStopColor.Free;
  887. inherited Destroy;
  888. end;
  889. //----------------------------------------------------------------------
  890. procedure TGLSkyDomeBand.Assign(Source: TPersistent);
  891. begin
  892. if Source is TGLSkyDomeBand then
  893. begin
  894. FStartAngle := TGLSkyDomeBand(Source).FStartAngle;
  895. FStopAngle := TGLSkyDomeBand(Source).FStopAngle;
  896. FStartColor.Assign(TGLSkyDomeBand(Source).FStartColor);
  897. FStopColor.Assign(TGLSkyDomeBand(Source).FStopColor);
  898. FSlices := TGLSkyDomeBand(Source).FSlices;
  899. FStacks := TGLSkyDomeBand(Source).FStacks;
  900. end;
  901. inherited Destroy;
  902. end;
  903. function TGLSkyDomeBand.GetDisplayName: string;
  904. begin
  905. Result := Format('%d: %.1f° - %.1f°', [Index, StartAngle, StopAngle]);
  906. end;
  907. procedure TGLSkyDomeBand.SetStartAngle(const val: Single);
  908. begin
  909. FStartAngle := ClampValue(val, -90, 90);
  910. if FStartAngle > FStopAngle then
  911. FStopAngle := FStartAngle;
  912. TGLSkyDomeBands(Collection).NotifyChange;
  913. end;
  914. procedure TGLSkyDomeBand.SetStartColor(const val: TGLColor);
  915. begin
  916. FStartColor.Assign(val);
  917. end;
  918. //----------------------------------------------------------------------
  919. procedure TGLSkyDomeBand.SetStopAngle(const val: Single);
  920. begin
  921. FStopAngle := ClampValue(val, -90, 90);
  922. if FStopAngle < FStartAngle then
  923. FStartAngle := FStopAngle;
  924. TGLSkyDomeBands(Collection).NotifyChange;
  925. end;
  926. procedure TGLSkyDomeBand.SetStopColor(const val: TGLColor);
  927. begin
  928. FStopColor.Assign(val);
  929. end;
  930. procedure TGLSkyDomeBand.SetSlices(const val: Integer);
  931. begin
  932. if val < 3 then
  933. FSlices := 3
  934. else
  935. FSlices := val;
  936. TGLSkyDomeBands(Collection).NotifyChange;
  937. end;
  938. procedure TGLSkyDomeBand.SetStacks(const val: Integer);
  939. begin
  940. if val < 1 then
  941. FStacks := 1
  942. else
  943. FStacks := val;
  944. TGLSkyDomeBands(Collection).NotifyChange;
  945. end;
  946. procedure TGLSkyDomeBand.OnColorChange(sender: TObject);
  947. begin
  948. TGLSkyDomeBands(Collection).NotifyChange;
  949. end;
  950. //----------------------------------------------------------------------
  951. procedure TGLSkyDomeBand.BuildList(var rci: TGLRenderContextInfo);
  952. // coordinates system note: X is forward, Y is left and Z is up
  953. // always rendered as sphere of radius 1
  954. procedure RenderBand(start, stop: Single;
  955. const colStart, colStop: TGLColorVector);
  956. var
  957. i: Integer;
  958. f, r, r2: Single;
  959. vertex1, vertex2: TGLVector;
  960. begin
  961. vertex1.W := 1;
  962. if start = -90 then
  963. begin
  964. // triangle fan with south pole
  965. gl.Begin_(GL_TRIANGLE_FAN);
  966. gl.Color4fv(@colStart);
  967. gl.Vertex3f(0, 0, -1);
  968. f := 2 * PI / Slices;
  969. SinCosine(DegToRadian(stop), vertex1.Z, r);
  970. gl.Color4fv(@colStop);
  971. for i := 0 to Slices do
  972. begin
  973. SinCosine(i * f, r, vertex1.Y, vertex1.X);
  974. gl.Vertex4fv(@vertex1);
  975. end;
  976. gl.End_;
  977. end
  978. else if stop = 90 then
  979. begin
  980. // triangle fan with north pole
  981. gl.Begin_(GL_TRIANGLE_FAN);
  982. gl.Color4fv(@colStop);
  983. gl.Vertex3fv(@ZHmgPoint);
  984. f := 2 * PI / Slices;
  985. SinCosine(DegToRadian(start), vertex1.Z, r);
  986. gl.Color4fv(@colStart);
  987. for i := Slices downto 0 do
  988. begin
  989. SinCosine(i * f, r, vertex1.Y, vertex1.X);
  990. gl.Vertex4fv(@vertex1);
  991. end;
  992. gl.End_;
  993. end
  994. else
  995. begin
  996. vertex2.W := 1;
  997. // triangle strip
  998. gl.Begin_(GL_TRIANGLE_STRIP);
  999. f := 2 * PI / Slices;
  1000. SinCosine(DegToRadian(start), vertex1.Z, r);
  1001. SinCosine(DegToRadian(stop), vertex2.Z, r2);
  1002. for i := 0 to Slices do
  1003. begin
  1004. SinCosine(i * f, r, vertex1.Y, vertex1.X);
  1005. gl.Color4fv(@colStart);
  1006. gl.Vertex4fv(@vertex1);
  1007. SinCosine(i * f, r2, vertex2.Y, vertex2.X);
  1008. gl.Color4fv(@colStop);
  1009. gl.Vertex4fv(@vertex2);
  1010. end;
  1011. gl.End_;
  1012. end;
  1013. end;
  1014. var
  1015. n: Integer;
  1016. t, t2: Single;
  1017. begin
  1018. if StartAngle = StopAngle then
  1019. Exit;
  1020. for n := 0 to Stacks - 1 do
  1021. begin
  1022. t := n / Stacks;
  1023. t2 := (n + 1) / Stacks;
  1024. RenderBand(Lerp(StartAngle, StopAngle, t), Lerp(StartAngle, StopAngle, t2),
  1025. VectorLerp(StartColor.Color, StopColor.Color, t),
  1026. VectorLerp(StartColor.Color, StopColor.Color, t2));
  1027. end;
  1028. end;
  1029. // ------------------
  1030. // ------------------ TGLSkyDomeBands ------------------
  1031. // ------------------
  1032. constructor TGLSkyDomeBands.Create(AOwner: TComponent);
  1033. begin
  1034. owner := AOwner;
  1035. inherited Create(TGLSkyDomeBand);
  1036. end;
  1037. function TGLSkyDomeBands.GetOwner: TPersistent;
  1038. begin
  1039. Result := owner;
  1040. end;
  1041. //----------------------------------------------------------------------
  1042. procedure TGLSkyDomeBands.SetItems(index: Integer; const val: TGLSkyDomeBand);
  1043. begin
  1044. inherited Items[index] := val;
  1045. end;
  1046. function TGLSkyDomeBands.GetItems(index: Integer): TGLSkyDomeBand;
  1047. begin
  1048. Result := TGLSkyDomeBand(inherited Items[index]);
  1049. end;
  1050. function TGLSkyDomeBands.Add: TGLSkyDomeBand;
  1051. begin
  1052. Result := (inherited Add) as TGLSkyDomeBand;
  1053. end;
  1054. function TGLSkyDomeBands.FindItemID(ID: Integer): TGLSkyDomeBand;
  1055. begin
  1056. Result := (inherited FindItemID(ID)) as TGLSkyDomeBand;
  1057. end;
  1058. procedure TGLSkyDomeBands.NotifyChange;
  1059. begin
  1060. if Assigned(owner) and (owner is TGLBaseSceneObject) then
  1061. TGLBaseSceneObject(owner).StructureChanged;
  1062. end;
  1063. procedure TGLSkyDomeBands.BuildList(var rci: TGLRenderContextInfo);
  1064. var
  1065. i: Integer;
  1066. begin
  1067. for i := 0 to Count - 1 do
  1068. Items[i].BuildList(rci);
  1069. end;
  1070. // ------------------
  1071. // ------------------ TGLSkyDomeStar ------------------
  1072. // ------------------
  1073. constructor TGLSkyDomeStar.Create(Collection: TCollection);
  1074. begin
  1075. inherited Create(Collection);
  1076. end;
  1077. destructor TGLSkyDomeStar.Destroy;
  1078. begin
  1079. inherited Destroy;
  1080. end;
  1081. procedure TGLSkyDomeStar.Assign(Source: TPersistent);
  1082. begin
  1083. if Source is TGLSkyDomeStar then
  1084. begin
  1085. FRA := TGLSkyDomeStar(Source).FRA;
  1086. FDec := TGLSkyDomeStar(Source).FDec;
  1087. FMagnitude := TGLSkyDomeStar(Source).FMagnitude;
  1088. FColor := TGLSkyDomeStar(Source).FColor;
  1089. SetVector(FCacheCoord, TGLSkyDomeStar(Source).FCacheCoord);
  1090. end;
  1091. inherited Destroy;
  1092. end;
  1093. //----------------------------------------------------------------------
  1094. function TGLSkyDomeStar.GetDisplayName: string;
  1095. begin
  1096. Result := Format('RA: %5.1f / Dec: %5.1f', [RA, DEC]);
  1097. end;
  1098. // ------------------
  1099. // ------------------ TGLSkyDomeStars ------------------
  1100. // ------------------
  1101. constructor TGLSkyDomeStars.Create(AOwner: TComponent);
  1102. begin
  1103. owner := AOwner;
  1104. inherited Create(TGLSkyDomeStar);
  1105. end;
  1106. function TGLSkyDomeStars.GetOwner: TPersistent;
  1107. begin
  1108. Result := owner;
  1109. end;
  1110. procedure TGLSkyDomeStars.SetItems(index: Integer; const val: TGLSkyDomeStar);
  1111. begin
  1112. inherited Items[index] := val;
  1113. end;
  1114. function TGLSkyDomeStars.GetItems(index: Integer): TGLSkyDomeStar;
  1115. begin
  1116. Result := TGLSkyDomeStar(inherited Items[index]);
  1117. end;
  1118. function TGLSkyDomeStars.Add: TGLSkyDomeStar;
  1119. begin
  1120. Result := (inherited Add) as TGLSkyDomeStar;
  1121. end;
  1122. function TGLSkyDomeStars.FindItemID(ID: Integer): TGLSkyDomeStar;
  1123. begin
  1124. Result := (inherited FindItemID(ID)) as TGLSkyDomeStar;
  1125. end;
  1126. //----------------------------------------------------------------------
  1127. procedure TGLSkyDomeStars.PrecomputeCartesianCoordinates;
  1128. var
  1129. i: Integer;
  1130. star: TGLSkyDomeStar;
  1131. raC, raS, decC, decS: Single;
  1132. begin
  1133. // to be enhanced...
  1134. for i := 0 to Count - 1 do
  1135. begin
  1136. star := Items[i];
  1137. SinCosine(star.DEC * cPIdiv180, decS, decC);
  1138. SinCosine(star.RA * cPIdiv180, decC, raS, raC);
  1139. star.FCacheCoord.X := raC;
  1140. star.FCacheCoord.Y := raS;
  1141. star.FCacheCoord.Z := decS;
  1142. end;
  1143. end;
  1144. //----------------------------------------------------------------------
  1145. procedure TGLSkyDomeStars.BuildList(var rci: TGLRenderContextInfo;
  1146. twinkle: Boolean);
  1147. var
  1148. i, n: Integer;
  1149. star: TGLSkyDomeStar;
  1150. lastColor: TColor;
  1151. lastPointSize10, pointSize10: Integer;
  1152. Color, twinkleColor: TGLColorVector;
  1153. (*sub*)procedure DoTwinkle;
  1154. begin
  1155. if (n and 63) = 0 then
  1156. begin
  1157. twinkleColor := VectorScale(Color, Random * 0.6 + 0.4);
  1158. gl.Color3fv(@twinkleColor.X);
  1159. n := 0;
  1160. end
  1161. else
  1162. Inc(n);
  1163. end;
  1164. begin
  1165. if Count = 0 then
  1166. Exit;
  1167. PrecomputeCartesianCoordinates;
  1168. lastColor := -1;
  1169. n := 0;
  1170. lastPointSize10 := -1;
  1171. rci.GLStates.Enable(stPointSmooth);
  1172. rci.GLStates.Enable(stAlphaTest);
  1173. rci.GLStates.SetGLAlphaFunction(cfNotEqual, 0.0);
  1174. rci.GLStates.Enable(stBlend);
  1175. rci.GLStates.SetBlendFunc(bfSrcAlpha, bfOne);
  1176. gl.Begin_(GL_POINTS);
  1177. for i := 0 to Count - 1 do
  1178. begin
  1179. star := Items[i];
  1180. pointSize10 := Round((4.5 - star.Magnitude) * 10);
  1181. if pointSize10 <> lastPointSize10 then
  1182. begin
  1183. if pointSize10 > 15 then
  1184. begin
  1185. gl.End_;
  1186. lastPointSize10 := pointSize10;
  1187. rci.GLStates.PointSize := pointSize10 * 0.1;
  1188. gl.Begin_(GL_POINTS);
  1189. end
  1190. else if lastPointSize10 <> 15 then
  1191. begin
  1192. gl.End_;
  1193. lastPointSize10 := 15;
  1194. rci.GLStates.PointSize := 1.5;
  1195. gl.Begin_(GL_POINTS);
  1196. end;
  1197. end;
  1198. if lastColor <> star.FColor then
  1199. begin
  1200. Color := ConvertWinColor(star.FColor);
  1201. if twinkle then
  1202. begin
  1203. n := 0;
  1204. DoTwinkle;
  1205. end
  1206. else
  1207. gl.Color3fv(@Color.X);
  1208. lastColor := star.FColor;
  1209. end
  1210. else if twinkle then
  1211. DoTwinkle;
  1212. gl.Vertex3fv(@star.FCacheCoord.X);
  1213. end;
  1214. gl.End_;
  1215. // restore default AlphaFunc
  1216. rci.GLStates.SetGLAlphaFunction(cfGreater, 0);
  1217. end;
  1218. //----------------------------------------------------------------------
  1219. procedure TGLSkyDomeStars.AddRandomStars(const nb: Integer; const Color: TColor;
  1220. const LimitToTopDome: Boolean = False);
  1221. var
  1222. i: Integer;
  1223. coord: TAffineVector;
  1224. star: TGLSkyDomeStar;
  1225. begin
  1226. for i := 1 to nb do
  1227. begin
  1228. star := Add;
  1229. // pick a point in the half-cube
  1230. if LimitToTopDome then
  1231. coord.Z := Random
  1232. else
  1233. coord.Z := Random * 2 - 1;
  1234. // calculate RA and Dec
  1235. star.DEC := ArcSin(coord.Z) * c180divPI;
  1236. star.RA := Random * 360 - 180;
  1237. // pick a color
  1238. star.Color := Color;
  1239. // pick a magnitude
  1240. star.Magnitude := 3;
  1241. end;
  1242. end;
  1243. //-----------------------------------------------------------------------
  1244. procedure TGLSkyDomeStars.AddRandomStars(const nb: Integer;
  1245. const ColorMin, ColorMax: TVector3b;
  1246. const Magnitude_min, Magnitude_max: Single;
  1247. const LimitToTopDome: Boolean = False);
  1248. function RandomTT(Min, Max: Byte): Byte;
  1249. begin
  1250. Result := Min + Random(Max - Min);
  1251. end;
  1252. var
  1253. i: Integer;
  1254. coord: TAffineVector;
  1255. star: TGLSkyDomeStar;
  1256. begin
  1257. for i := 1 to nb do
  1258. begin
  1259. star := Add;
  1260. // pick a point in the half-cube
  1261. if LimitToTopDome then
  1262. coord.Z := Random
  1263. else
  1264. coord.Z := Random * 2 - 1;
  1265. // calculate RA and Dec
  1266. star.DEC := ArcSin(coord.Z) * c180divPI;
  1267. star.RA := Random * 360 - 180;
  1268. // pick a color
  1269. star.Color := RGB2Color(RandomTT(ColorMin.X, ColorMax.X),
  1270. RandomTT(ColorMin.Y, ColorMax.Y), RandomTT(ColorMin.Z, ColorMax.Z));
  1271. // pick a magnitude
  1272. star.Magnitude := Magnitude_min + Random * (Magnitude_max - Magnitude_min);
  1273. end;
  1274. end;
  1275. //----------------------------------------------------------------------
  1276. procedure TGLSkyDomeStars.LoadStarsFile(const starsFileName: string);
  1277. var
  1278. fs: TFileStream;
  1279. sr: TGLStarRecord;
  1280. colorVector: TGLColorVector;
  1281. begin
  1282. fs := TFileStream.Create(starsFileName, fmOpenRead + fmShareDenyWrite);
  1283. try
  1284. while fs.Position < fs.Size do
  1285. begin
  1286. fs.Read(sr, SizeOf(sr));
  1287. with Add do
  1288. begin
  1289. RA := sr.RA * 0.01;
  1290. DEC := sr.DEC * 0.01;
  1291. colorVector := StarRecordColor(sr, 3);
  1292. Magnitude := sr.VMagnitude * 0.05; // default 0.1
  1293. if sr.VMagnitude > 35 then
  1294. Color := ConvertColorVector(colorVector, colorVector.W)
  1295. else
  1296. Color := ConvertColorVector(colorVector);
  1297. end;
  1298. end;
  1299. finally
  1300. fs.Free;
  1301. end;
  1302. end;
  1303. // ------------------
  1304. // ------------------ TGLSkyDome ------------------
  1305. // ------------------
  1306. constructor TGLSkyDome.Create(AOwner: TComponent);
  1307. begin
  1308. inherited Create(AOwner);
  1309. CamInvarianceMode := cimPosition;
  1310. ObjectStyle := ObjectStyle + [osDirectDraw, osNoVisibilityCulling];
  1311. FBands := TGLSkyDomeBands.Create(Self);
  1312. with FBands.Add do
  1313. begin
  1314. StartAngle := 0;
  1315. StartColor.Color := clrWhite;
  1316. StopAngle := 15;
  1317. StopColor.Color := clrBlue;
  1318. end;
  1319. with FBands.Add do
  1320. begin
  1321. StartAngle := 15;
  1322. StartColor.Color := clrBlue;
  1323. StopAngle := 90;
  1324. Stacks := 4;
  1325. StopColor.Color := clrNavy;
  1326. end;
  1327. FStars := TGLSkyDomeStars.Create(Self);
  1328. end;
  1329. destructor TGLSkyDome.Destroy;
  1330. begin
  1331. FStars.Free;
  1332. FBands.Free;
  1333. inherited Destroy;
  1334. end;
  1335. //----------------------------------------------------------------------
  1336. procedure TGLSkyDome.Assign(Source: TPersistent);
  1337. begin
  1338. if Source is TGLSkyDome then
  1339. begin
  1340. FBands.Assign(TGLSkyDome(Source).FBands);
  1341. FStars.Assign(TGLSkyDome(Source).FStars);
  1342. end;
  1343. inherited;
  1344. end;
  1345. //----------------------------------------------------------------------
  1346. procedure TGLSkyDome.SetBands(const val: TGLSkyDomeBands);
  1347. begin
  1348. FBands.Assign(val);
  1349. StructureChanged;
  1350. end;
  1351. procedure TGLSkyDome.SetStars(const val: TGLSkyDomeStars);
  1352. begin
  1353. FStars.Assign(val);
  1354. StructureChanged;
  1355. end;
  1356. //--------- Options to draw grids and twinkle stars --------
  1357. procedure TGLSkyDome.SetOptions(const val: TGLSkyDomeOptions);
  1358. begin
  1359. if val <> FOptions then
  1360. begin
  1361. FOptions := val;
  1362. if sdoTwinkle in FOptions then
  1363. ObjectStyle := ObjectStyle + [osDirectDraw]
  1364. else
  1365. begin
  1366. ObjectStyle := ObjectStyle - [osDirectDraw];
  1367. DestroyHandle;
  1368. end;
  1369. StructureChanged;
  1370. end;
  1371. end;
  1372. //----------------------------------------------------------------------
  1373. procedure TGLSkyDome.BuildList(var rci: TGLRenderContextInfo);
  1374. var
  1375. f: Single;
  1376. begin
  1377. // setup states
  1378. with rci.GLStates do
  1379. begin
  1380. Disable(stLighting);
  1381. Disable(stDepthTest);
  1382. Disable(stFog);
  1383. Disable(stCullFace);
  1384. Disable(stBlend);
  1385. DepthWriteMask := False;
  1386. PolygonMode := pmFill;
  1387. end;
  1388. f := rci.rcci.farClippingDistance * 0.90;
  1389. gl.Scalef(f, f, f);
  1390. Bands.BuildList(rci);
  1391. Stars.BuildList(rci, (sdoTwinkle in FOptions));
  1392. end;
  1393. // ------------------
  1394. // ------------------ TGLEarthSkyDome ------------------
  1395. // ------------------
  1396. constructor TGLEarthSkyDome.Create(AOwner: TComponent);
  1397. begin
  1398. inherited Create(AOwner);
  1399. FMorning := true;
  1400. Bands.Clear;
  1401. FSunElevation := 75;
  1402. FTurbidity := 15;
  1403. FSunZenithColor := TGLColor.CreateInitialized(Self, clrWhite, OnColorChanged);
  1404. FSunDawnColor := TGLColor.CreateInitialized(Self, Vectormake(1, 0.5, 0, 0),
  1405. OnColorChanged);
  1406. FHazeColor := TGLColor.CreateInitialized(Self, Vectormake(0.9, 0.95, 1, 0),
  1407. OnColorChanged);
  1408. FSkyColor := TGLColor.CreateInitialized(Self, Vectormake(0.45, 0.6, 0.9, 0),
  1409. OnColorChanged);
  1410. FNightColor := TGLColor.CreateInitialized(Self, clrTransparent,
  1411. OnColorChanged);
  1412. FDeepColor := TGLColor.CreateInitialized(Self, Vectormake(0, 0.2, 0.4, 0));
  1413. FStacks := 24;
  1414. FSlices := 48;
  1415. PreCalculate;
  1416. end;
  1417. //----------------------------------------------------------------------
  1418. destructor TGLEarthSkyDome.Destroy;
  1419. begin
  1420. FSunZenithColor.Free;
  1421. FSunDawnColor.Free;
  1422. FHazeColor.Free;
  1423. FSkyColor.Free;
  1424. FNightColor.Free;
  1425. FDeepColor.Free;
  1426. inherited Destroy;
  1427. end;
  1428. //----------------------------------------------------------------------
  1429. procedure TGLEarthSkyDome.Assign(Source: TPersistent);
  1430. begin
  1431. if Source is TGLSkyDome then
  1432. begin
  1433. FSunElevation := TGLEarthSkyDome(Source).SunElevation;
  1434. FTurbidity := TGLEarthSkyDome(Source).Turbidity;
  1435. FSunZenithColor.Assign(TGLEarthSkyDome(Source).FSunZenithColor);
  1436. FSunDawnColor.Assign(TGLEarthSkyDome(Source).FSunDawnColor);
  1437. FHazeColor.Assign(TGLEarthSkyDome(Source).FHazeColor);
  1438. FSkyColor.Assign(TGLEarthSkyDome(Source).FSkyColor);
  1439. FNightColor.Assign(TGLEarthSkyDome(Source).FNightColor);
  1440. FSlices := TGLEarthSkyDome(Source).FSlices;
  1441. FStacks := TGLEarthSkyDome(Source).FStacks;
  1442. PreCalculate;
  1443. end;
  1444. inherited;
  1445. end;
  1446. procedure TGLEarthSkyDome.Loaded;
  1447. begin
  1448. inherited;
  1449. PreCalculate;
  1450. end;
  1451. //----------------------------------------------------------------------
  1452. procedure TGLEarthSkyDome.SetSunElevation(const val: Single);
  1453. var
  1454. newVal: Single;
  1455. begin
  1456. newVal := ClampValue(val, -90, 90);
  1457. if FSunElevation <> newVal then
  1458. begin
  1459. FSunElevation := newVal;
  1460. PreCalculate;
  1461. end;
  1462. end;
  1463. procedure TGLEarthSkyDome.SetTurbidity(const val: Single);
  1464. begin
  1465. FTurbidity := ClampValue(val, 1, 120);
  1466. PreCalculate;
  1467. end;
  1468. procedure TGLEarthSkyDome.SetSunZenithColor(const val: TGLColor);
  1469. begin
  1470. FSunZenithColor.Assign(val);
  1471. PreCalculate;
  1472. end;
  1473. procedure TGLEarthSkyDome.SetSunDawnColor(const val: TGLColor);
  1474. begin
  1475. FSunDawnColor.Assign(val);
  1476. PreCalculate;
  1477. end;
  1478. procedure TGLEarthSkyDome.SetHazeColor(const val: TGLColor);
  1479. begin
  1480. FHazeColor.Assign(val);
  1481. PreCalculate;
  1482. end;
  1483. procedure TGLEarthSkyDome.SetSkyColor(const val: TGLColor);
  1484. begin
  1485. FSkyColor.Assign(val);
  1486. PreCalculate;
  1487. end;
  1488. procedure TGLEarthSkyDome.SetNightColor(const val: TGLColor);
  1489. begin
  1490. FNightColor.Assign(val);
  1491. PreCalculate;
  1492. end;
  1493. procedure TGLEarthSkyDome.SetDeepColor(const val: TGLColor);
  1494. begin
  1495. FDeepColor.Assign(val);
  1496. PreCalculate;
  1497. end;
  1498. procedure TGLEarthSkyDome.SetSlices(const val: Integer);
  1499. begin
  1500. if val > 6 then
  1501. FSlices := val
  1502. else
  1503. FSlices := 6;
  1504. StructureChanged;
  1505. end;
  1506. procedure TGLEarthSkyDome.SetStacks(const val: Integer);
  1507. begin
  1508. if val > 1 then
  1509. FStacks := val
  1510. else
  1511. FStacks := 1;
  1512. StructureChanged;
  1513. end;
  1514. //----------------------------------------------------------------------
  1515. procedure TGLEarthSkyDome.BuildList(var rci: TGLRenderContextInfo);
  1516. var
  1517. f: Single;
  1518. begin
  1519. // setup states
  1520. with rci.GLStates do
  1521. begin
  1522. CurrentProgram := 0;
  1523. Disable(stLighting);
  1524. if esoDepthTest in FExtendedOptions then
  1525. begin
  1526. Enable(stDepthTest);
  1527. DepthFunc := cfLEqual;
  1528. end
  1529. else
  1530. Disable(stDepthTest);
  1531. Disable(stFog);
  1532. Disable(stCullFace);
  1533. Disable(stBlend);
  1534. Disable(stAlphaTest);
  1535. DepthWriteMask := False;
  1536. PolygonMode := pmFill;
  1537. end;
  1538. f := rci.rcci.farClippingDistance * 0.95;
  1539. gl.Scalef(f, f, f);
  1540. RenderDome;
  1541. Bands.BuildList(rci);
  1542. Stars.BuildList(rci, (sdoTwinkle in FOptions));
  1543. // restore
  1544. rci.GLStates.DepthWriteMask := true;
  1545. end;
  1546. procedure TGLEarthSkyDome.OnColorChanged(sender: TObject);
  1547. begin
  1548. PreCalculate;
  1549. end;
  1550. //----------------------------------------------------------------------
  1551. procedure TGLEarthSkyDome.SetSunAtTime(HH, MM: Single);
  1552. const
  1553. cHourToElevation1: array [0 .. 23] of Single = (-45, -67.5, -90, -57.5, -45,
  1554. -22.5, 0, 11.25, 22.5, 33.7, 45, 56.25, 67.5, 78.75, 90, 78.75, 67.5, 56.25,
  1555. 45, 33.7, 22.5, 11.25, 0, -22.5);
  1556. cHourToElevation2: array [0 .. 23] of Single = (-0.375, -0.375, 0.375, 0.375,
  1557. 0.375, 0.375, 0.1875, 0.1875, 0.1875, 0.1875, 0.1875, 0.1875, 0.1875,
  1558. 0.1875, -0.1875, -0.1875, -0.1875, -0.1875, -0.1875, -0.1875, -0.1875,
  1559. -0.1875, -0.375, -0.375);
  1560. var
  1561. ts: Single;
  1562. fts: Single;
  1563. i: Integer;
  1564. Color: TColor;
  1565. begin
  1566. HH := Round(HH);
  1567. if HH < 0 then
  1568. HH := 0;
  1569. if HH > 23 then
  1570. HH := 23;
  1571. if MM < 0 then
  1572. MM := 0;
  1573. if MM >= 60 then
  1574. begin
  1575. MM := 0;
  1576. HH := HH + 1;
  1577. if HH > 23 then
  1578. HH := 0;
  1579. end;
  1580. FSunElevation := cHourToElevation1[Round(HH)] + cHourToElevation2
  1581. [Round(HH)] * MM;
  1582. ts := DegToRadian(90 - FSunElevation);
  1583. // Mix base colors
  1584. fts := exp(-6 * (PI / 2 - ts));
  1585. VectorLerp(SunZenithColor.Color, SunDawnColor.Color, fts, FCurSunColor);
  1586. fts := IntPower(1 - cos(ts - 0.5), 2);
  1587. VectorLerp(HazeColor.Color, NightColor.Color, fts, FCurHazeColor);
  1588. VectorLerp(SkyColor.Color, NightColor.Color, fts, FCurSkyColor);
  1589. // Precalculate Turbidity factors
  1590. FCurHazeTurbid := -sqrt(121 - Turbidity) * 2;
  1591. FCurSunSkyTurbid := -(121 - Turbidity);
  1592. // fade stars if required
  1593. if SunElevation > -40 then
  1594. ts := PowerInteger(1 - (SunElevation + 40) / 90, 11)
  1595. else
  1596. ts := 1;
  1597. Color := RGB2Color(Round(ts * 255), Round(ts * 255), Round(ts * 255));
  1598. if esoFadeStarsWithSun in ExtendedOptions then
  1599. for i := 0 to Stars.Count - 1 do
  1600. Stars[i].Color := Color;
  1601. if esoRotateOnTwelveHours in ExtendedOptions then // spining around blue orb
  1602. begin
  1603. if (HH >= 14) and (FMorning) then
  1604. begin
  1605. roll(180);
  1606. for i := 0 to Stars.Count - 1 do
  1607. Stars[i].RA := Stars[i].RA + 180;
  1608. FMorning := False;
  1609. end;
  1610. if (HH >= 2) and (HH < 14) and (not FMorning) then
  1611. begin
  1612. roll(180);
  1613. for i := 0 to Stars.Count - 1 do
  1614. Stars[i].RA := Stars[i].RA + 180;
  1615. FMorning := true;
  1616. end;
  1617. end;
  1618. StructureChanged;
  1619. end;
  1620. //----------------------------------------------------------------------
  1621. procedure TGLEarthSkyDome.PreCalculate;
  1622. var
  1623. ts: Single;
  1624. fts: Single;
  1625. i: Integer;
  1626. Color: TColor;
  1627. begin
  1628. ts := DegToRadian(90 - SunElevation);
  1629. // Precompose base colors
  1630. fts := exp(-6 * (PI / 2 - ts));
  1631. VectorLerp(SunZenithColor.Color, SunDawnColor.Color, fts, FCurSunColor);
  1632. fts := PowerInteger(1 - cos(ts - 0.5), 2);
  1633. VectorLerp(HazeColor.Color, NightColor.Color, fts, FCurHazeColor);
  1634. VectorLerp(SkyColor.Color, NightColor.Color, fts, FCurSkyColor);
  1635. // Precalculate Turbidity factors
  1636. FCurHazeTurbid := -sqrt(121 - Turbidity) * 2;
  1637. FCurSunSkyTurbid := -(121 - Turbidity);
  1638. // fade stars if required
  1639. if SunElevation > -40 then
  1640. ts := PowerInteger(1 - (SunElevation + 40) / 90, 11)
  1641. else
  1642. ts := 1;
  1643. Color := RGB2Color(Round(ts * 255), Round(ts * 255), Round(ts * 255));
  1644. if esoFadeStarsWithSun in ExtendedOptions then
  1645. for i := 0 to Stars.Count - 1 do
  1646. Stars[i].Color := Color;
  1647. if esoRotateOnTwelveHours in ExtendedOptions then
  1648. begin
  1649. if SunElevation = 90 then
  1650. begin
  1651. roll(180);
  1652. for i := 0 to Stars.Count - 1 do
  1653. Stars[i].RA := Stars[i].RA + 180;
  1654. end
  1655. else if SunElevation = -90 then
  1656. begin
  1657. roll(180);
  1658. for i := 0 to Stars.Count - 1 do
  1659. Stars[i].RA := Stars[i].RA + 180;
  1660. end;
  1661. end;
  1662. StructureChanged;
  1663. end;
  1664. //----------------------------------------------------------------------
  1665. function TGLEarthSkyDome.CalculateColor(const theta, cosGamma: Single)
  1666. : TGLColorVector;
  1667. var
  1668. t: Single;
  1669. begin
  1670. t := PI / 2 - theta;
  1671. // mix to get haze/sky
  1672. VectorLerp(FCurSkyColor, FCurHazeColor, ClampValue(exp(FCurHazeTurbid * t), 0,
  1673. 1), Result);
  1674. // then mix sky with sun
  1675. VectorLerp(Result, FCurSunColor,
  1676. ClampValue(exp(FCurSunSkyTurbid * cosGamma * (1 + t)) * 1.1, 0, 1), Result);
  1677. end;
  1678. //----------------------------------------------------------------------
  1679. procedure TGLEarthSkyDome.RenderDome;
  1680. var
  1681. ts: Single;
  1682. steps: Integer;
  1683. sunPos: TAffineVector;
  1684. sinTable, cosTable: PFloatArray;
  1685. (*sub*)function CalculateCosGamma(const p: TGLVector): Single;
  1686. begin
  1687. Result := 1 - VectorAngleCosine(PAffineVector(@p)^, sunPos);
  1688. end;
  1689. (*sub*)procedure RenderDeepBand(stop: Single);
  1690. var
  1691. i: Integer;
  1692. r, thetaStart: Single;
  1693. vertex1: TGLVector;
  1694. Color: TGLColorVector;
  1695. begin
  1696. r := 0;
  1697. vertex1.W := 1;
  1698. // triangle fan with south pole
  1699. gl.Begin_(GL_TRIANGLE_FAN);
  1700. Color := CalculateColor(0, CalculateCosGamma(ZHmgPoint));
  1701. gl.Color4fv(DeepColor.AsAddress);
  1702. gl.Vertex3f(0, 0, -1);
  1703. SinCosine(DegToRadian(stop), vertex1.Z, r);
  1704. thetaStart := DegToRadian(90 - stop);
  1705. for i := 0 to steps - 1 do
  1706. begin
  1707. vertex1.X := r * cosTable[i];
  1708. vertex1.Y := r * sinTable[i];
  1709. Color := CalculateColor(thetaStart, CalculateCosGamma(vertex1));
  1710. gl.Color4fv(@Color);
  1711. gl.Vertex4fv(@vertex1);
  1712. end;
  1713. gl.End_;
  1714. end;
  1715. (*sub*)procedure RenderBand(start, stop: Single);
  1716. var
  1717. i: Integer;
  1718. r, r2, thetaStart, thetaStop: Single;
  1719. vertex1, vertex2: TGLVector;
  1720. Color: TGLColorVector;
  1721. begin
  1722. vertex1.W := 1;
  1723. if stop = 90 then
  1724. begin
  1725. // triangle fan with north pole
  1726. gl.Begin_(GL_TRIANGLE_FAN);
  1727. Color := CalculateColor(0, CalculateCosGamma(ZHmgPoint));
  1728. gl.Color4fv(@Color);
  1729. gl.Vertex4fv(@ZHmgPoint);
  1730. SinCosine(DegToRadian(start), vertex1.Z, r);
  1731. thetaStart := DegToRadian(90 - start);
  1732. for i := 0 to steps - 1 do
  1733. begin
  1734. vertex1.X := r * cosTable[i];
  1735. vertex1.Y := r * sinTable[i];
  1736. Color := CalculateColor(thetaStart, CalculateCosGamma(vertex1));
  1737. gl.Color4fv(@Color);
  1738. gl.Vertex4fv(@vertex1);
  1739. end;
  1740. gl.End_;
  1741. end
  1742. else
  1743. begin
  1744. vertex2.W := 1;
  1745. // triangle strip
  1746. gl.Begin_(GL_TRIANGLE_STRIP);
  1747. SinCosine(DegToRadian(start), vertex1.Z, r);
  1748. SinCosine(DegToRadian(stop), vertex2.Z, r2);
  1749. thetaStart := DegToRadian(90 - start);
  1750. thetaStop := DegToRadian(90 - stop);
  1751. for i := 0 to steps - 1 do
  1752. begin
  1753. vertex1.X := r * cosTable[i];
  1754. vertex1.Y := r * sinTable[i];
  1755. Color := CalculateColor(thetaStart, CalculateCosGamma(vertex1));
  1756. gl.Color4fv(@Color);
  1757. gl.Vertex4fv(@vertex1);
  1758. vertex2.X := r2 * cosTable[i];
  1759. vertex2.Y := r2 * sinTable[i];
  1760. Color := CalculateColor(thetaStop, CalculateCosGamma(vertex2));
  1761. gl.Color4fv(@Color);
  1762. gl.Vertex4fv(@vertex2);
  1763. end;
  1764. gl.End_;
  1765. end;
  1766. end;
  1767. var
  1768. n, i, sdiv2: Integer;
  1769. t, t2, p, fs: Single;
  1770. begin
  1771. ts := DegToRadian(90 - SunElevation);
  1772. SetVector(sunPos, sin(ts), 0, cos(ts));
  1773. // prepare sin/cos LUT, with a higher sampling around 0Ѝ
  1774. n := Slices div 2;
  1775. steps := 2 * n + 1;
  1776. GetMem(sinTable, steps * SizeOf(Single));
  1777. GetMem(cosTable, steps * SizeOf(Single));
  1778. for i := 1 to n do
  1779. begin
  1780. p := (1 - sqrt(cos((i / n) * cPIdiv2))) * PI;
  1781. SinCosine(p, sinTable[n + i], cosTable[n + i]);
  1782. sinTable[n - i] := -sinTable[n + i];
  1783. cosTable[n - i] := cosTable[n + i];
  1784. end;
  1785. // these are defined by hand for precision issue: the dome must wrap exactly
  1786. sinTable[n] := 0;
  1787. cosTable[n] := 1;
  1788. sinTable[0] := 0;
  1789. cosTable[0] := -1;
  1790. sinTable[steps - 1] := 0;
  1791. cosTable[steps - 1] := -1;
  1792. fs := SunElevation / 90;
  1793. // start render
  1794. t := 0;
  1795. sdiv2 := Stacks div 2;
  1796. for n := 0 to Stacks - 1 do
  1797. begin
  1798. if fs > 0 then
  1799. begin
  1800. if n < sdiv2 then
  1801. t2 := fs - fs * Sqr((sdiv2 - n) / sdiv2)
  1802. else
  1803. t2 := fs + Sqr((n - sdiv2) / (sdiv2 - 1)) * (1 - fs);
  1804. end
  1805. else
  1806. t2 := (n + 1) / Stacks;
  1807. RenderBand(Lerp(1, 90, t), Lerp(1, 90, t2));
  1808. t := t2;
  1809. end;
  1810. RenderDeepBand(1);
  1811. FreeMem(sinTable);
  1812. FreeMem(cosTable);
  1813. end;
  1814. // -------------------------------------------------------------
  1815. initialization
  1816. // -------------------------------------------------------------
  1817. RegisterClasses([TGLSkyBox, TGLSkyDome, TGLEarthSkyDome]);
  1818. end.