GLS.GeomObjects.pas 111 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646
  1. //
  2. // The graphics engine GLScene
  3. //
  4. unit GLS.GeomObjects;
  5. (*
  6. Geometric objects.
  7. The registered classes are:
  8. [TGLDodecahedron, TGLIcosahedron, TGLHexahedron, TGLOctahedron, TGLTetrahedron,
  9. TGLCylinder, TGLCone, TGLTorus, TGLDisk, TGLArrowLine, TGLAnnulus,
  10. TGLFrustrum, TGLPolygon, TGLCapsule, TGLArrowArc, TGLTeapot]
  11. *)
  12. interface
  13. {$I Stage.Defines.inc}
  14. uses
  15. Winapi.OpenGL,
  16. System.Math,
  17. System.Classes,
  18. GLS.OpenGLAdapter,
  19. Stage.OpenGLTokens,
  20. Stage.VectorTypes,
  21. Stage.VectorGeometry,
  22. Stage.PipelineTransform,
  23. Stage.Polynomials,
  24. GLS.Scene,
  25. GLS.State,
  26. GLS.PersistentClasses,
  27. GLS.VectorLists,
  28. GLS.Silhouette,
  29. GLS.GeometryBB,
  30. GLS.VectorFileObjects,
  31. GLS.Material,
  32. GLS.Texture,
  33. GLS.Context,
  34. GLS.Objects,
  35. GLS.Mesh,
  36. GLS.RenderContextInfo,
  37. GLS.XOpenGL;
  38. type
  39. //-------------------- TGLBaseMesh Objects -----------------------
  40. (* This objects has no texture coordinates defined, ie. without using
  41. a texture generation mode, no texture will be mapped. *)
  42. TGLTetrahedron = class(TGLBaseMesh)
  43. public
  44. procedure BuildList(var rci: TGLRenderContextInfo); override;
  45. end;
  46. TGLOctahedron = class(TGLBaseMesh)
  47. public
  48. procedure BuildList(var rci: TGLRenderContextInfo); override;
  49. end;
  50. TGLHexahedron = class(TGLBaseMesh)
  51. public
  52. procedure BuildList(var rci: TGLRenderContextInfo); override;
  53. end;
  54. TGLDodecahedron = class(TGLBaseMesh)
  55. public
  56. procedure BuildList(var rci: TGLRenderContextInfo); override;
  57. end;
  58. TGLIcosahedron = class(TGLBaseMesh)
  59. public
  60. procedure BuildList(var rci: TGLRenderContextInfo); override;
  61. end;
  62. //--------------------------- TGLQuadric Objects -------------------
  63. (* A Disk object that may not be complete, it can have a hole (controlled by the
  64. InnerRadius property) and can only be a slice (controlled by the StartAngle
  65. and SweepAngle properties). *)
  66. TGLDisk = class(TGLQuadricObject)
  67. private
  68. FStartAngle, FSweepAngle, FOuterRadius, FInnerRadius: Single;
  69. FSlices, FLoops: Integer;
  70. procedure SetOuterRadius(const aValue: Single);
  71. procedure SetInnerRadius(const aValue: Single);
  72. procedure SetSlices(aValue: Integer);
  73. procedure SetLoops(aValue: Integer);
  74. procedure SetStartAngle(const aValue: Single);
  75. procedure SetSweepAngle(const aValue: Single);
  76. public
  77. constructor Create(AOwner: TComponent); override;
  78. procedure BuildList(var rci: TGLRenderContextInfo); override;
  79. procedure Assign(Source: TPersistent); override;
  80. function AxisAlignedDimensionsUnscaled: TGLVector; override;
  81. function RayCastIntersect(const rayStart, rayVector: TGLVector;
  82. intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil) : Boolean; override;
  83. published
  84. // Allows defining a "hole" in the disk
  85. property InnerRadius: Single read FInnerRadius write SetInnerRadius;
  86. // Number of radial mesh subdivisions
  87. property Loops: Integer read FLoops write SetLoops default 2;
  88. // Outer radius for the disk. If you leave InnerRadius at 0, this is the disk radius
  89. property OuterRadius: Single read FOuterRadius write SetOuterRadius;
  90. // Number of mesh slices. For instance, if Slices=6, your disk will look like an hexagon
  91. property Slices: Integer read FSlices write SetSlices default 16;
  92. property StartAngle: Single read FStartAngle write SetStartAngle;
  93. property SweepAngle: Single read FSweepAngle write SetSweepAngle;
  94. end;
  95. (* Base class to cylinder-like objects that introduces the basic cylinder description properties.
  96. Be aware teh default slices and stacks make up for a high-poly cylinder,
  97. unless you're after high-quality lighting it is recommended to reduce the
  98. Stacks property to 1. *)
  99. TGLCylinderBase = class(TGLQuadricObject)
  100. private
  101. FBottomRadius: Single;
  102. FSlices, FStacks, FLoops: Integer;
  103. FHeight: Single;
  104. protected
  105. procedure SetBottomRadius(const aValue: Single);
  106. procedure SetHeight(const aValue: Single);
  107. procedure SetSlices(aValue: Integer);
  108. procedure SetStacks(aValue: Integer);
  109. procedure SetLoops(aValue: Integer);
  110. function GetTopRadius: Single; virtual;
  111. public
  112. constructor Create(AOwner: TComponent); override;
  113. procedure Assign(Source: TPersistent); override;
  114. function GenerateSilhouette(const silhouetteParameters
  115. : TGLSilhouetteParameters): TGLSilhouette; override;
  116. published
  117. property BottomRadius: Single read FBottomRadius write SetBottomRadius;
  118. property Height: Single read FHeight write SetHeight;
  119. property Slices: Integer read FSlices write SetSlices default 16;
  120. property Stacks: Integer read FStacks write SetStacks default 4;
  121. // Number of concentric rings for top/bottom disk(s).
  122. property Loops: Integer read FLoops write SetLoops default 1;
  123. end;
  124. TGLConePart = (coSides, coBottom);
  125. TGLConeParts = set of TGLConePart;
  126. // A cone object
  127. TGLCone = class(TGLCylinderBase)
  128. private
  129. FParts: TGLConeParts;
  130. protected
  131. procedure SetParts(aValue: TGLConeParts);
  132. function GetTopRadius: Single; override;
  133. public
  134. constructor Create(AOwner: TComponent); override;
  135. procedure Assign(Source: TPersistent); override;
  136. procedure BuildList(var rci: TGLRenderContextInfo); override;
  137. function AxisAlignedDimensionsUnscaled: TGLVector; override;
  138. function RayCastIntersect(const rayStart, rayVector: TGLVector;
  139. intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil)
  140. : Boolean; override;
  141. published
  142. property Parts: TGLConeParts read FParts write SetParts
  143. default [coSides, coBottom];
  144. end;
  145. TGLCylinderPart = (cySides, cyBottom, cyTop);
  146. TGLCylinderParts = set of TGLCylinderPart;
  147. TGLCylinderAlignment = (caCenter, caTop, caBottom);
  148. // Cylinder object, can also be used to make truncated cones
  149. TGLCylinder = class(TGLCylinderBase)
  150. private
  151. FParts: TGLCylinderParts;
  152. FTopRadius: Single;
  153. FAlignment: TGLCylinderAlignment;
  154. protected
  155. procedure SetTopRadius(const aValue: Single);
  156. procedure SetParts(aValue: TGLCylinderParts);
  157. procedure SetAlignment(val: TGLCylinderAlignment);
  158. function GetTopRadius: Single; override;
  159. public
  160. constructor Create(AOwner: TComponent); override;
  161. procedure Assign(Source: TPersistent); override;
  162. procedure BuildList(var rci: TGLRenderContextInfo); override;
  163. function AxisAlignedDimensionsUnscaled: TGLVector; override;
  164. function RayCastIntersect(const rayStart, rayVector: TGLVector;
  165. intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil)
  166. : Boolean; override;
  167. procedure Align(const startPoint, endPoint: TGLVector); overload;
  168. procedure Align(const startObj, endObj: TGLBaseSceneObject); overload;
  169. procedure Align(const startPoint, endPoint: TAffineVector); overload;
  170. published
  171. property TopRadius: Single read FTopRadius write SetTopRadius;
  172. property Parts: TGLCylinderParts read FParts write SetParts
  173. default [cySides, cyBottom, cyTop];
  174. property Alignment: TGLCylinderAlignment read FAlignment write SetAlignment
  175. default caCenter;
  176. end;
  177. // Capsule object, can also be used to make truncated cones
  178. TGLCapsule = class(TGLSceneObject)
  179. private
  180. FParts: TGLCylinderParts;
  181. FRadius: Single;
  182. FSlices: Integer;
  183. FStacks: Integer;
  184. FHeight: Single;
  185. FAlignment: TGLCylinderAlignment;
  186. protected
  187. procedure SetHeight(const aValue: Single);
  188. procedure SetRadius(const aValue: Single);
  189. procedure SetSlices(const aValue: integer);
  190. procedure SetStacks(const aValue: integer);
  191. procedure SetParts(aValue: TGLCylinderParts);
  192. procedure SetAlignment(val: TGLCylinderAlignment);
  193. public
  194. constructor Create(AOwner: TComponent); override;
  195. procedure Assign(Source: TPersistent); override;
  196. procedure BuildList(var rci: TGLRenderContextInfo); override;
  197. function AxisAlignedDimensionsUnscaled: TGLVector; override;
  198. function RayCastIntersect(const rayStart, rayVector: TGLVector;
  199. intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil)
  200. : Boolean; override;
  201. procedure Align(const startPoint, endPoint: TGLVector); overload;
  202. procedure Align(const startObj, endObj: TGLBaseSceneObject); overload;
  203. procedure Align(const startPoint, endPoint: TAffineVector); overload;
  204. published
  205. property Height: Single read FHeight write SetHeight;
  206. property Slices: Integer read FSlices write SetSlices;
  207. property Stacks: Integer read FStacks write SetStacks;
  208. property Radius: Single read FRadius write SetRadius;
  209. property Parts: TGLCylinderParts read FParts write SetParts
  210. default [cySides, cyBottom, cyTop];
  211. property Alignment: TGLCylinderAlignment read FAlignment write SetAlignment
  212. default caCenter;
  213. end;
  214. TGLAnnulusPart = (anInnerSides, anOuterSides, anBottom, anTop);
  215. TGLAnnulusParts = set of TGLAnnulusPart;
  216. // An annulus is a cylinder that can be made hollow (pipe-like)
  217. TGLAnnulus = class(TGLCylinderBase)
  218. private
  219. FParts: TGLAnnulusParts;
  220. FBottomInnerRadius: Single;
  221. FTopInnerRadius: Single;
  222. FTopRadius: Single;
  223. protected
  224. procedure SetTopRadius(const aValue: Single);
  225. procedure SetTopInnerRadius(const aValue: Single);
  226. procedure SetBottomInnerRadius(const aValue: Single);
  227. procedure SetParts(aValue: TGLAnnulusParts);
  228. public
  229. constructor Create(AOwner: TComponent); override;
  230. procedure Assign(Source: TPersistent); override;
  231. procedure BuildList(var rci: TGLRenderContextInfo); override;
  232. function AxisAlignedDimensionsUnscaled: TGLVector; override;
  233. function RayCastIntersect(const rayStart, rayVector: TGLVector;
  234. intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil)
  235. : Boolean; override;
  236. published
  237. property BottomInnerRadius: Single read FBottomInnerRadius
  238. write SetBottomInnerRadius;
  239. property TopInnerRadius: Single read FTopInnerRadius
  240. write SetTopInnerRadius;
  241. property TopRadius: Single read FTopRadius write SetTopRadius;
  242. property Parts: TGLAnnulusParts read FParts write SetParts
  243. default [anInnerSides, anOuterSides, anBottom, anTop];
  244. end;
  245. TGLTorusPart = (toSides, toStartDisk, toStopDisk);
  246. TGLTorusParts = set of TGLTorusPart;
  247. // A Torus object
  248. TGLTorus = class(TGLSceneObject)
  249. private
  250. FParts: TGLTorusParts;
  251. FRings, FSides: Cardinal;
  252. FStartAngle, FStopAngle: Single;
  253. FMinorRadius, FMajorRadius: Single;
  254. FMesh: array of array of TGLVertexRec;
  255. protected
  256. procedure SetMajorRadius(const aValue: Single);
  257. procedure SetMinorRadius(const aValue: Single);
  258. procedure SetRings(aValue: Cardinal);
  259. procedure SetSides(aValue: Cardinal);
  260. procedure SetStartAngle(const aValue: Single);
  261. procedure SetStopAngle(const aValue: Single);
  262. procedure SetParts(aValue: TGLTorusParts);
  263. public
  264. constructor Create(AOwner: TComponent); override;
  265. procedure BuildList(var rci: TGLRenderContextInfo); override;
  266. function AxisAlignedDimensionsUnscaled: TGLVector; override;
  267. function RayCastIntersect(const rayStart, rayVector: TGLVector;
  268. intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil): Boolean; override;
  269. published
  270. property MajorRadius: Single read FMajorRadius write SetMajorRadius;
  271. property MinorRadius: Single read FMinorRadius write SetMinorRadius;
  272. property Rings: Cardinal read FRings write SetRings default 25;
  273. property Sides: Cardinal read FSides write SetSides default 15;
  274. property StartAngle: Single read FStartAngle write SetStartAngle;
  275. property StopAngle: Single read FStopAngle write SetStopAngle;
  276. property Parts: TGLTorusParts read FParts write SetParts default [toSides];
  277. end;
  278. TGLArrowLinePart = (alLine, alTopArrow, alBottomArrow);
  279. TGLArrowLineParts = set of TGLArrowLinePart;
  280. TGLArrowHeadStyle = (ahssStacked, ahssCentered, ahssIncluded);
  281. (* Draws an arrowhead (cylinder + cone).
  282. The arrow head is a cone that shares the attributes of the cylinder
  283. (ie stacks/slices, materials etc). Seems to work ok.
  284. This is useful for displaying a vector based field (eg velocity) or
  285. other arrows that might be required.
  286. By default the bottom arrow is off *)
  287. TGLArrowLine = class(TGLCylinderBase)
  288. private
  289. FParts: TGLArrowLineParts;
  290. FTopRadius: Single;
  291. fTopArrowHeadHeight: Single;
  292. fTopArrowHeadRadius: Single;
  293. fBottomArrowHeadHeight: Single;
  294. fBottomArrowHeadRadius: Single;
  295. FHeadStackingStyle: TGLArrowHeadStyle;
  296. protected
  297. procedure SetTopRadius(const aValue: Single);
  298. procedure SetTopArrowHeadHeight(const aValue: Single);
  299. procedure SetTopArrowHeadRadius(const aValue: Single);
  300. procedure SetBottomArrowHeadHeight(const aValue: Single);
  301. procedure SetBottomArrowHeadRadius(const aValue: Single);
  302. procedure SetParts(aValue: TGLArrowLineParts);
  303. procedure SetHeadStackingStyle(const val: TGLArrowHeadStyle);
  304. public
  305. constructor Create(AOwner: TComponent); override;
  306. procedure BuildList(var rci: TGLRenderContextInfo); override;
  307. procedure Assign(Source: TPersistent); override;
  308. published
  309. property TopRadius: Single read FTopRadius write SetTopRadius;
  310. property HeadStackingStyle: TGLArrowHeadStyle read FHeadStackingStyle
  311. write SetHeadStackingStyle default ahssStacked;
  312. property Parts: TGLArrowLineParts read FParts write SetParts
  313. default [alLine, alTopArrow];
  314. property TopArrowHeadHeight: Single read fTopArrowHeadHeight
  315. write SetTopArrowHeadHeight;
  316. property TopArrowHeadRadius: Single read fTopArrowHeadRadius
  317. write SetTopArrowHeadRadius;
  318. property BottomArrowHeadHeight: Single read fBottomArrowHeadHeight
  319. write SetBottomArrowHeadHeight;
  320. property BottomArrowHeadRadius: Single read fBottomArrowHeadRadius
  321. write SetBottomArrowHeadRadius;
  322. end;
  323. TGLArrowArcPart = (aaArc, aaTopArrow, aaBottomArrow);
  324. TGLArrowArcParts = set of TGLArrowArcPart;
  325. (* Draws an arrowhead (Sliced Torus + cone).
  326. The arrow head is a cone that shares the attributes of the Torus
  327. (ie stacks/slices, materials etc).
  328. This is useful for displaying a movement (eg twist) or
  329. other arc arrows that might be required.
  330. By default the bottom arrow is off *)
  331. TGLArrowArc = class(TGLCylinderBase)
  332. private
  333. fArcRadius: Single;
  334. FStartAngle: Single;
  335. FStopAngle: Single;
  336. FParts: TGLArrowArcParts;
  337. FTopRadius: Single;
  338. fTopArrowHeadHeight: Single;
  339. fTopArrowHeadRadius: Single;
  340. fBottomArrowHeadHeight: Single;
  341. fBottomArrowHeadRadius: Single;
  342. FHeadStackingStyle: TGLArrowHeadStyle;
  343. FMesh: array of array of TGLVertexRec;
  344. protected
  345. procedure SetArcRadius(const aValue: Single);
  346. procedure SetStartAngle(const aValue: Single);
  347. procedure SetStopAngle(const aValue: Single);
  348. procedure SetTopRadius(const aValue: Single);
  349. procedure SetTopArrowHeadHeight(const aValue: Single);
  350. procedure SetTopArrowHeadRadius(const aValue: Single);
  351. procedure SetBottomArrowHeadHeight(const aValue: Single);
  352. procedure SetBottomArrowHeadRadius(const aValue: Single);
  353. procedure SetParts(aValue: TGLArrowArcParts);
  354. procedure SetHeadStackingStyle(const val: TGLArrowHeadStyle);
  355. public
  356. constructor Create(AOwner: TComponent); override;
  357. procedure BuildList(var rci: TGLRenderContextInfo); override;
  358. procedure Assign(Source: TPersistent); override;
  359. published
  360. property ArcRadius: Single read fArcRadius write SetArcRadius;
  361. property StartAngle: Single read FStartAngle write SetStartAngle;
  362. property StopAngle: Single read FStopAngle write SetStopAngle;
  363. property TopRadius: Single read FTopRadius write SetTopRadius;
  364. property HeadStackingStyle: TGLArrowHeadStyle read FHeadStackingStyle
  365. write SetHeadStackingStyle default ahssStacked;
  366. property Parts: TGLArrowArcParts read FParts write SetParts
  367. default [aaArc, aaTopArrow];
  368. property TopArrowHeadHeight: Single read fTopArrowHeadHeight
  369. write SetTopArrowHeadHeight;
  370. property TopArrowHeadRadius: Single read fTopArrowHeadRadius
  371. write SetTopArrowHeadRadius;
  372. property BottomArrowHeadHeight: Single read fBottomArrowHeadHeight
  373. write SetBottomArrowHeadHeight;
  374. property BottomArrowHeadRadius: Single read fBottomArrowHeadRadius
  375. write SetBottomArrowHeadRadius;
  376. end;
  377. TGLPolygonPart = (ppTop, ppBottom);
  378. TGLPolygonParts = set of TGLPolygonPart;
  379. (* A basic polygon object.
  380. The contour is described by the Nodes and SplineMode properties, it should be
  381. planar and is automatically tessellated.
  382. Texture coordinates are deduced from X and Y coordinates only.
  383. This object allows only for polygons described by a single contour, if you
  384. need "complex polygons" with holes, patches and cutouts, see GLS.MultiPolygon. *)
  385. TGLPolygon = class(TGLPolygonBase)
  386. private
  387. FParts: TGLPolygonParts;
  388. protected
  389. procedure SetParts(const val: TGLPolygonParts);
  390. public
  391. constructor Create(AOwner: TComponent); override;
  392. destructor Destroy; override;
  393. procedure Assign(Source: TPersistent); override;
  394. procedure BuildList(var rci: TGLRenderContextInfo); override;
  395. published
  396. (* Parts of polygon.
  397. The 'top' of the polygon is the position were the curve describing
  398. the polygon spin counter-clockwise (i.e. right handed convention). *)
  399. property Parts: TGLPolygonParts read FParts write SetParts default [ppTop, ppBottom];
  400. end;
  401. TGLFrustrumPart = (fpTop, fpBottom, fpFront, fpBack, fpLeft, fpRight);
  402. TGLFrustrumParts = set of TGLFrustrumPart;
  403. const
  404. cAllFrustrumParts = [fpTop, fpBottom, fpFront, fpBack, fpLeft, fpRight];
  405. type
  406. (* A frustrum is a pyramid with the top chopped off.
  407. The height of the imaginary pyramid is ApexHeight, the height of the
  408. frustrum is Height. If ApexHeight and Height are the same, the frustrum
  409. degenerates into a pyramid.
  410. Height cannot be greater than ApexHeight. *)
  411. TGLFrustrum = class(TGLSceneObject)
  412. private
  413. FApexHeight, FBaseDepth, FBaseWidth, FHeight: Single;
  414. FParts: TGLFrustrumParts;
  415. FNormalDirection: TGLNormalDirection;
  416. procedure SetApexHeight(const aValue: Single);
  417. procedure SetBaseDepth(const aValue: Single);
  418. procedure SetBaseWidth(const aValue: Single);
  419. procedure SetHeight(const aValue: Single);
  420. procedure SetParts(aValue: TGLFrustrumParts);
  421. procedure SetNormalDirection(aValue: TGLNormalDirection);
  422. protected
  423. procedure DefineProperties(Filer: TFiler); override;
  424. procedure ReadData(Stream: TStream);
  425. procedure WriteData(Stream: TStream);
  426. public
  427. constructor Create(AOwner: TComponent); override;
  428. procedure BuildList(var rci: TGLRenderContextInfo); override;
  429. procedure Assign(Source: TPersistent); override;
  430. function TopDepth: Single;
  431. function TopWidth: Single;
  432. function AxisAlignedBoundingBoxUnscaled: TAABB;
  433. function AxisAlignedDimensionsUnscaled: TGLVector; override;
  434. published
  435. property ApexHeight: Single read FApexHeight write SetApexHeight stored False;
  436. property BaseDepth: Single read FBaseDepth write SetBaseDepth stored False;
  437. property BaseWidth: Single read FBaseWidth write SetBaseWidth stored False;
  438. property Height: Single read FHeight write SetHeight stored False;
  439. property NormalDirection: TGLNormalDirection read FNormalDirection
  440. write SetNormalDirection default ndOutside;
  441. property Parts: TGLFrustrumParts read FParts write SetParts default cAllFrustrumParts;
  442. end;
  443. //--------------------- TGLTeapot -------------------------
  444. (* The classic teapot.
  445. The only use of this object is as placeholder for testing... *)
  446. TGLTeapot = class(TGLSceneObject)
  447. private
  448. FGrid: Cardinal;
  449. public
  450. constructor Create(AOwner: TComponent); override;
  451. function AxisAlignedDimensionsUnscaled: TGLVector; override;
  452. procedure BuildList(var rci: TGLRenderContextInfo); override;
  453. procedure DoRender(var ARci: TGLRenderContextInfo;
  454. ARenderSelf, ARenderChildren: Boolean); override;
  455. end;
  456. // -------------------------------------------------------------
  457. implementation
  458. // -------------------------------------------------------------
  459. //--------------------
  460. //-------------------- TGLTetrahedron ------------------------
  461. //--------------------
  462. procedure TGLTetrahedron.BuildList(var rci: TGLRenderContextInfo);
  463. const
  464. Vertices: packed array [0 .. 3] of TAffineVector =
  465. ((X: 0.5; Y: 0.5; Z: 0.5), // 0
  466. (X: 0.5; Y: -0.5; Z: -0.5), // 1
  467. (X: -0.5; Y: 0.5; Z: -0.5), // 2
  468. (X: -0.5; Y: -0.5; Z: 0.5)); // 3
  469. Triangles: packed array [0 .. 3] of packed array [0 .. 2] of Byte =
  470. ((0, 1, 3), // 0
  471. (2, 1, 0), // 1
  472. (3, 2, 0), // 2
  473. (1, 2, 3)); // 3
  474. var
  475. i, j: Integer;
  476. n: TAffineVector;
  477. faceIndices: PByteArray;
  478. begin
  479. for i := 0 to 3 do
  480. begin
  481. faceIndices := @triangles[i, 0];
  482. n := CalcPlaneNormal(vertices[faceIndices^[0]], vertices[faceIndices^[1]],
  483. vertices[faceIndices^[2]]);
  484. gl.Normal3fv(@n);
  485. gl.Begin_(GL_TRIANGLES);
  486. for j := 0 to 2 do
  487. gl.Vertex3fv(@vertices[faceIndices^[j]]);
  488. gl.End_;
  489. end;
  490. end;
  491. //--------------------
  492. //-------------------- TGLOctahedron ------------------------
  493. //--------------------
  494. procedure TGLOctahedron.BuildList(var rci: TGLRenderContextInfo);
  495. const
  496. Vertices: packed array [0 .. 5] of TAffineVector =
  497. ((X: 1.0; Y: 0.0; Z: 0.0), // 0
  498. (X:-1.0; Y: 0.0; Z: 0.0), // 1
  499. (X: 0.0; Y: 1.0; Z: 0.0), // 2
  500. (X: 0.0; Y: -1.0; Z: 0.0), // 3
  501. (X: 0.0; Y: 0.0; Z: 1.0), // 4
  502. (X: 0.0; Y: 0.0; Z: -1.0)); // 5
  503. Triangles: packed array [0 .. 7] of packed array [0 .. 2] of Byte =
  504. ((0, 4, 2), // 0
  505. (1, 2, 4), // 1
  506. (0, 3, 4), // 2
  507. (1, 4, 3), // 3
  508. (0, 2, 5), // 4
  509. (1, 5, 2), // 5
  510. (0, 5, 3), // 6
  511. (1, 3, 5)); // 7
  512. var
  513. i, j: Integer;
  514. n: TAffineVector;
  515. faceIndices: PByteArray;
  516. begin
  517. for i := 0 to 7 do
  518. begin
  519. faceIndices := @triangles[i, 0];
  520. n := CalcPlaneNormal(vertices[faceIndices^[0]], vertices[faceIndices^[1]],
  521. vertices[faceIndices^[2]]);
  522. gl.Normal3fv(@n);
  523. gl.Begin_(GL_TRIANGLES);
  524. for j := 0 to 2 do
  525. gl.Vertex3fv(@vertices[faceIndices^[j]]);
  526. gl.End_;
  527. end;
  528. end;
  529. // ------------------
  530. // ------------------ TGLHexahedron ------------------
  531. // ------------------
  532. procedure TGLHexahedron.BuildList(var rci: TGLRenderContextInfo);
  533. const
  534. Vertices: packed array [0 .. 7] of TAffineVector =
  535. ((X:-1; Y:-1; Z:-1),
  536. (X: 1; Y:-1; Z:-1),
  537. (X: 1; Y:-1; Z: 1),
  538. (X:-1; Y:-1; Z: 1),
  539. (X:-1; Y: 1; Z:-1),
  540. (X: 1; Y: 1; Z:-1),
  541. (X: 1; Y: 1; Z: 1),
  542. (X:-1; Y: 1; Z: 1));
  543. Quadrangles: packed array [0 .. 5] of packed array [0 .. 3] of Byte =
  544. ((0, 1, 2, 3),
  545. (3, 2, 6, 7),
  546. (7, 6, 5, 4),
  547. (4, 5, 1, 0),
  548. (0, 3, 7, 4),
  549. (1, 5, 6, 2));
  550. var
  551. i, j: Integer;
  552. n: TAffineVector;
  553. faceIndices: PByteArray;
  554. begin
  555. for i := 0 to 4 do
  556. begin
  557. faceIndices := @Quadrangles[i, 0];
  558. n := CalcPlaneNormal(vertices[faceIndices^[0]],
  559. vertices[faceIndices^[1]], vertices[faceIndices^[2]]);
  560. gl.Normal3fv(@n);
  561. gl.Begin_(GL_QUADS);
  562. for j := 0 to 7 do
  563. gl.Vertex3fv(@vertices[faceIndices^[j]]);
  564. gl.End_;
  565. end;
  566. end;
  567. // ------------------
  568. // ------------------ TGLIcosahedron ------------------
  569. // ------------------
  570. procedure TGLIcosahedron.BuildList(var rci: TGLRenderContextInfo);
  571. const
  572. B = 0.309017; // 1/(1+Sqrt(5))
  573. const
  574. Vertices: packed array [0 .. 11] of TAffineVector =
  575. ((X: 0; Y: - B; Z: - 0.5), // 0
  576. (X: 0; Y: - B; Z: 0.5), // 1
  577. (X: 0; Y: B; Z: - 0.5), // 2
  578. (X: 0; Y: B; Z: 0.5), // 3
  579. (X: - 0.5; Y: 0; Z: - B), // 4
  580. (X: - 0.5; Y: 0; Z: B), // 5
  581. (X: 0.5; Y: 0; Z: - B), // 6
  582. (X: 0.5; Y: 0; Z: B), // 7
  583. (X: - B; Y: - 0.5; Z: 0), // 8
  584. (X: - B; Y: 0.5; Z: 0), // 9
  585. (X: B; Y: - 0.5; Z: 0), // 10
  586. (X: B; Y: 0.5; Z: 0)); // 11
  587. Triangles: packed array [0 .. 19] of packed array [0 .. 2] of Byte =
  588. ((2, 9, 11), // 0
  589. (3, 11, 9), // 1
  590. (3, 5, 1), // 2
  591. (3, 1, 7), // 3
  592. (2, 6, 0), // 4
  593. (2, 0, 4), // 5
  594. (1, 8, 10), // 6
  595. (0, 10, 8), // 7
  596. (9, 4, 5), // 8
  597. (8, 5, 4), // 9
  598. (11, 7, 6), // 10
  599. (10, 6, 7), // 11
  600. (3, 9, 5), // 12
  601. (3, 7, 11), // 13
  602. (2, 4, 9), // 14
  603. (2, 11, 6), // 15
  604. (0, 8, 4), // 16
  605. (0, 6, 10), // 17
  606. (1, 5, 8), // 18
  607. (1, 10, 7)); // 19
  608. var
  609. i, j: Integer;
  610. n: TAffineVector;
  611. faceIndices: PByteArray;
  612. begin
  613. for i := 0 to 19 do
  614. begin
  615. faceIndices := @triangles[i, 0];
  616. n := CalcPlaneNormal(vertices[faceIndices^[0]], vertices[faceIndices^[1]],
  617. vertices[faceIndices^[2]]);
  618. gl.Normal3fv(@n);
  619. gl.Begin_(GL_TRIANGLES);
  620. for j := 0 to 2 do
  621. gl.Vertex3fv(@vertices[faceIndices^[j]]);
  622. gl.End_;
  623. end;
  624. end;
  625. // ------------------
  626. // ------------------ TGLDodecahedron ------------------
  627. // ------------------
  628. procedure TGLDodecahedron.BuildList(var rci: TGLRenderContextInfo);
  629. const
  630. A = 1.61803398875 * 0.3; // (Sqrt(5)+1)/2
  631. B = 0.61803398875 * 0.3; // (Sqrt(5)-1)/2
  632. C = 1 * 0.3;
  633. const
  634. Vertices: packed array [0 .. 19] of TAffineVector =
  635. ((X: - A; Y: 0; Z: B), (X: - A; Y: 0; Z: - B), (X: A; Y: 0; Z: - B),
  636. (X: A; Y: 0; Z: B), (X: B; Y: - A; Z: 0), (X: - B; Y: - A; Z: 0),
  637. (X: - B; Y: A; Z: 0), (X: B; Y: A; Z: 0), (X: 0; Y: B; Z: - A),
  638. (X: 0; Y: - B; Z: - A), (X: 0; Y: - B; Z: A), (X: 0; Y: B; Z: A),
  639. (X: - C; Y: - C; Z: C), (X: - C; Y: - C; Z: - C), (X: C; Y: - C; Z: - C),
  640. (X: C; Y: - C; Z: C), (X: - C; Y: C; Z: C), (X: - C; Y: C; Z: - C),
  641. (X: C; Y: C; Z: - C), (X: C; Y: C; Z: C));
  642. Polygons: packed array [0 .. 11] of packed array [0 .. 4] of Byte =
  643. ((0, 12, 10, 11, 16), (1, 17, 8, 9, 13), (2, 14, 9, 8, 18),
  644. (3, 19, 11, 10, 15), (4, 14, 2, 3, 15), (5, 12, 0, 1, 13),
  645. (6, 17, 1, 0, 16), (7, 19, 3, 2, 18), (8, 17, 6, 7, 18),
  646. (9, 14, 4, 5, 13), (10, 12, 5, 4, 15), (11, 19, 7, 6, 16));
  647. var
  648. i, j: Integer;
  649. n: TAffineVector;
  650. faceIndices: PByteArray;
  651. begin
  652. for i := 0 to 11 do
  653. begin
  654. faceIndices := @polygons[i, 0];
  655. n := CalcPlaneNormal(vertices[faceIndices^[0]], vertices[faceIndices^[1]],
  656. vertices[faceIndices^[2]]);
  657. gl.Normal3fv(@n);
  658. // gl.Begin_(GL_TRIANGLE_FAN);
  659. // for j := 0 to 4 do
  660. // gl.Vertex3fv(@vertices[faceIndices^[j]]);
  661. // gl.End_();
  662. gl.Begin_(GL_TRIANGLES);
  663. for j := 1 to 3 do
  664. begin
  665. gl.Vertex3fv(@vertices[faceIndices^[0]]);
  666. gl.Vertex3fv(@vertices[faceIndices^[j]]);
  667. gl.Vertex3fv(@vertices[faceIndices^[j+1]]);
  668. end;
  669. gl.End_;
  670. end;
  671. end;
  672. // ------------------
  673. // ------------------ TGLDisk ------------------
  674. // ------------------
  675. constructor TGLDisk.Create(AOwner: TComponent);
  676. begin
  677. inherited Create(AOwner);
  678. FOuterRadius := 0.5;
  679. FInnerRadius := 0;
  680. FSlices := 16;
  681. FLoops := 2;
  682. FStartAngle := 0;
  683. FSweepAngle := 360;
  684. end;
  685. procedure TGLDisk.BuildList(var rci: TGLRenderContextInfo);
  686. var
  687. quadric: PGLUquadric;
  688. begin
  689. quadric := gluNewQuadric();
  690. SetupQuadricParams(quadric);
  691. gluPartialDisk(quadric, FInnerRadius, FOuterRadius, FSlices, FLoops,
  692. FStartAngle, FSweepAngle);
  693. gluDeleteQuadric(quadric);
  694. end;
  695. procedure TGLDisk.SetOuterRadius(const aValue: Single);
  696. begin
  697. if aValue <> FOuterRadius then
  698. begin
  699. FOuterRadius := aValue;
  700. StructureChanged;
  701. end;
  702. end;
  703. procedure TGLDisk.SetInnerRadius(const aValue: Single);
  704. begin
  705. if aValue <> FInnerRadius then
  706. begin
  707. FInnerRadius := aValue;
  708. StructureChanged;
  709. end;
  710. end;
  711. procedure TGLDisk.SetSlices(aValue: integer);
  712. begin
  713. if aValue <> FSlices then
  714. begin
  715. FSlices := aValue;
  716. StructureChanged;
  717. end;
  718. end;
  719. procedure TGLDisk.SetLoops(aValue: integer);
  720. begin
  721. if aValue <> FLoops then
  722. begin
  723. FLoops := aValue;
  724. StructureChanged;
  725. end;
  726. end;
  727. procedure TGLDisk.SetStartAngle(const aValue: Single);
  728. begin
  729. if aValue <> FStartAngle then
  730. begin
  731. FStartAngle := aValue;
  732. StructureChanged;
  733. end;
  734. end;
  735. procedure TGLDisk.SetSweepAngle(const aValue: Single);
  736. begin
  737. if aValue <> FSweepAngle then
  738. begin
  739. FSweepAngle := aValue;
  740. StructureChanged;
  741. end;
  742. end;
  743. procedure TGLDisk.Assign(Source: TPersistent);
  744. begin
  745. if Assigned(Source) and (Source is TGLDisk) then
  746. begin
  747. FOuterRadius := TGLDisk(Source).FOuterRadius;
  748. FInnerRadius := TGLDisk(Source).FInnerRadius;
  749. FSlices := TGLDisk(Source).FSlices;
  750. FLoops := TGLDisk(Source).FLoops;
  751. FStartAngle := TGLDisk(Source).FStartAngle;
  752. FSweepAngle := TGLDisk(Source).FSweepAngle;
  753. end;
  754. inherited Assign(Source);
  755. end;
  756. function TGLDisk.AxisAlignedDimensionsUnscaled: TGLVector;
  757. var
  758. r: Single;
  759. begin
  760. r := Abs(FOuterRadius);
  761. Result := VectorMake(r, r, 0);
  762. end;
  763. function TGLDisk.RayCastIntersect(const rayStart, rayVector: TGLVector;
  764. intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil): Boolean;
  765. var
  766. ip: TGLVector;
  767. d: Single;
  768. angle, beginAngle, endAngle: Single;
  769. localIntPoint: TGLVector;
  770. begin
  771. Result := False;
  772. if SweepAngle > 0 then
  773. if RayCastPlaneIntersect(rayStart, rayVector, AbsolutePosition,
  774. AbsoluteDirection, @ip) then
  775. begin
  776. if Assigned(intersectPoint) then
  777. SetVector(intersectPoint^, ip);
  778. localIntPoint := AbsoluteToLocal(ip);
  779. d := VectorNorm(localIntPoint);
  780. if (d >= Sqr(InnerRadius)) and (d <= Sqr(OuterRadius)) then
  781. begin
  782. if SweepAngle >= 360 then
  783. Result := true
  784. else
  785. begin
  786. // arctan2 returns results between -pi and +pi, we want between 0 and 360
  787. angle := 180 / pi * ArcTan2(localIntPoint.X, localIntPoint.Y);
  788. if angle < 0 then
  789. angle := angle + 360;
  790. // we also want StartAngle and StartAngle+SweepAngle to be in this range
  791. beginAngle := Trunc(StartAngle) mod 360;
  792. endAngle := Trunc(StartAngle + SweepAngle) mod 360;
  793. // If beginAngle > endAngle then area crosses the boundary from 360=>0 degrees
  794. // therefore have 2 valid regions (beginAngle to 360) & (0 to endAngle)
  795. // otherwise just 1 valid region (beginAngle to endAngle)
  796. if beginAngle > endAngle then
  797. begin
  798. if (angle > beginAngle) or (angle < endAngle) then
  799. Result := true;
  800. end
  801. else if (angle > beginAngle) and (angle < endAngle) then
  802. Result := true;
  803. end;
  804. end;
  805. end;
  806. if Result = true then
  807. if Assigned(intersectNormal) then
  808. SetVector(intersectNormal^, AbsoluteUp);
  809. end;
  810. // ------------------
  811. // ------------------ TGLCylinderBase ------------------
  812. // ------------------
  813. constructor TGLCylinderBase.Create(AOwner: TComponent);
  814. begin
  815. inherited Create(AOwner);
  816. FBottomRadius := 0.5;
  817. FHeight := 1;
  818. FSlices := 16;
  819. FStacks := 4;
  820. FLoops := 1;
  821. end;
  822. procedure TGLCylinderBase.SetBottomRadius(const aValue: Single);
  823. begin
  824. if aValue <> FBottomRadius then
  825. begin
  826. FBottomRadius := aValue;
  827. StructureChanged;
  828. end;
  829. end;
  830. function TGLCylinderBase.GetTopRadius: Single;
  831. begin
  832. Result := FBottomRadius;
  833. end;
  834. procedure TGLCylinderBase.SetHeight(const aValue: Single);
  835. begin
  836. if aValue <> FHeight then
  837. begin
  838. FHeight := aValue;
  839. StructureChanged;
  840. end;
  841. end;
  842. procedure TGLCylinderBase.SetSlices(aValue: Integer);
  843. begin
  844. if aValue <> FSlices then
  845. begin
  846. FSlices := aValue;
  847. StructureChanged;
  848. end;
  849. end;
  850. procedure TGLCylinderBase.SetStacks(aValue: Integer);
  851. begin
  852. if aValue <> FStacks then
  853. begin
  854. FStacks := aValue;
  855. StructureChanged;
  856. end;
  857. end;
  858. procedure TGLCylinderBase.SetLoops(aValue: Integer);
  859. begin
  860. if (aValue >= 1) and (aValue <> FLoops) then
  861. begin
  862. FLoops := aValue;
  863. StructureChanged;
  864. end;
  865. end;
  866. procedure TGLCylinderBase.Assign(Source: TPersistent);
  867. begin
  868. if Assigned(Source) and (Source is TGLCylinderBase) then
  869. begin
  870. FBottomRadius := TGLCylinderBase(Source).FBottomRadius;
  871. FSlices := TGLCylinderBase(Source).FSlices;
  872. FStacks := TGLCylinderBase(Source).FStacks;
  873. FLoops := TGLCylinderBase(Source).FLoops;
  874. FHeight := TGLCylinderBase(Source).FHeight;
  875. end;
  876. inherited Assign(Source);
  877. end;
  878. function TGLCylinderBase.GenerateSilhouette(const silhouetteParameters
  879. : TGLSilhouetteParameters): TGLSilhouette;
  880. var
  881. Connectivity: TGLConnectivity;
  882. sil: TGLSilhouette;
  883. ShadowSlices: integer;
  884. i: integer;
  885. p: array [0 .. 3] of TVector3f;
  886. PiDivSlices: Single;
  887. a1, a2: Single;
  888. c1, c2: TVector3f;
  889. cosa1, cosa2, sina1, sina2: Single;
  890. HalfHeight: Single;
  891. ShadowTopRadius: Single;
  892. begin
  893. Connectivity := TGLConnectivity.Create(true);
  894. ShadowSlices := FSlices div 1;
  895. if FSlices < 5 then
  896. FSlices := 5;
  897. PiDivSlices := 2 * pi / ShadowSlices;
  898. a1 := 0;
  899. // Is this a speed improvement or just a waste of code?
  900. HalfHeight := FHeight / 2;
  901. MakeVector(c1, 0, -HalfHeight, 0);
  902. MakeVector(c2, 0, HalfHeight, 0);
  903. ShadowTopRadius := GetTopRadius;
  904. for i := 0 to ShadowSlices - 1 do
  905. begin
  906. a2 := a1 + PiDivSlices;
  907. // Is this a speed improvement or just a waste of code?
  908. cosa1 := cos(a1);
  909. cosa2 := cos(a2);
  910. sina1 := sin(a1);
  911. sina2 := sin(a2);
  912. // Generate the four "corners";
  913. // Bottom corners
  914. MakeVector(p[0], FBottomRadius * sina2, -HalfHeight, FBottomRadius * cosa2);
  915. MakeVector(p[1], FBottomRadius * sina1, -HalfHeight, FBottomRadius * cosa1);
  916. // Top corners
  917. MakeVector(p[2], ShadowTopRadius * sina1, HalfHeight, ShadowTopRadius * cosa1);
  918. MakeVector(p[3], ShadowTopRadius * sina2, HalfHeight, ShadowTopRadius * cosa2);
  919. // This should be optimized to use AddIndexedFace, because this method
  920. // searches for each of the vertices and adds them or re-uses them.
  921. // Skin
  922. Connectivity.AddFace(p[2], p[1], p[0]);
  923. Connectivity.AddFace(p[3], p[2], p[0]);
  924. // Sides / caps
  925. Connectivity.AddFace(c1, p[0], p[1]);
  926. Connectivity.AddFace(p[2], p[3], c2);
  927. a1 := a1 + PiDivSlices;
  928. end;
  929. sil := nil;
  930. Connectivity.CreateSilhouette(silhouetteParameters, sil, False);
  931. Result := sil;
  932. Connectivity.Free;
  933. end;
  934. // ------------------
  935. // ------------------ TGLCone ------------------
  936. // ------------------
  937. constructor TGLCone.Create(AOwner: TComponent);
  938. begin
  939. inherited Create(AOwner);
  940. FParts := [coSides, coBottom];
  941. end;
  942. procedure TGLCone.BuildList(var rci: TGLRenderContextInfo);
  943. var
  944. quadric: PGLUquadricObj;
  945. begin
  946. gl.PushMatrix;
  947. quadric := gluNewQuadric();
  948. SetupQuadricParams(quadric);
  949. gl.Rotated(-90, 1, 0, 0);
  950. gl.Translatef(0, 0, -FHeight * 0.5);
  951. if coSides in FParts then
  952. gluCylinder(quadric, BottomRadius, 0, Height, Slices, Stacks);
  953. if coBottom in FParts then
  954. begin
  955. // top of a disk is defined as outside
  956. SetInvertedQuadricOrientation(quadric);
  957. gluDisk(quadric, 0, BottomRadius, Slices, FLoops);
  958. end;
  959. gluDeleteQuadric(quadric);
  960. gl.PopMatrix;
  961. end;
  962. procedure TGLCone.SetParts(aValue: TGLConeParts);
  963. begin
  964. if aValue <> FParts then
  965. begin
  966. FParts := aValue;
  967. StructureChanged;
  968. end;
  969. end;
  970. procedure TGLCone.Assign(Source: TPersistent);
  971. begin
  972. if Assigned(Source) and (Source is TGLCone) then
  973. begin
  974. FParts := TGLCone(Source).FParts;
  975. end;
  976. inherited Assign(Source);
  977. end;
  978. function TGLCone.AxisAlignedDimensionsUnscaled: TGLVector;
  979. var
  980. r: Single;
  981. begin
  982. r := Abs(FBottomRadius);
  983. Result := VectorMake(r (* *Scale.DirectX *) , 0.5 * FHeight (* *Scale.DirectY *) ,
  984. r (* *Scale.DirectZ *) );
  985. end;
  986. function TGLCone.GetTopRadius: Single;
  987. begin
  988. Result := 0;
  989. end;
  990. function TGLCone.RayCastIntersect(const rayStart, rayVector: TGLVector;
  991. intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil): Boolean;
  992. var
  993. ip, localRayStart, localRayVector: TGLVector;
  994. poly: array [0 .. 2] of Double;
  995. roots: TDoubleArray;
  996. minRoot: Double;
  997. d, t, hconst: Single;
  998. begin
  999. Result := False;
  1000. localRayStart := AbsoluteToLocal(rayStart);
  1001. localRayVector := VectorNormalize(AbsoluteToLocal(rayVector));
  1002. if coBottom in Parts then
  1003. begin
  1004. // bottom can only be raycast from beneath
  1005. if localRayStart.Y < -FHeight * 0.5 then
  1006. begin
  1007. if RayCastPlaneIntersect(localRayStart, localRayVector,
  1008. PointMake(0, -FHeight * 0.5, 0), YHmgVector, @ip) then
  1009. begin
  1010. d := VectorNorm(ip.X, ip.Z);
  1011. if (d <= Sqr(BottomRadius)) then
  1012. begin
  1013. Result := true;
  1014. if Assigned(intersectPoint) then
  1015. SetVector(intersectPoint^, LocalToAbsolute(ip));
  1016. if Assigned(intersectNormal) then
  1017. SetVector(intersectNormal^, VectorNegate(AbsoluteUp));
  1018. Exit;
  1019. end;
  1020. end;
  1021. end;
  1022. end;
  1023. if coSides in Parts then
  1024. begin
  1025. hconst := -Sqr(BottomRadius) / Sqr(Height);
  1026. // intersect against infinite cones (in positive and negative direction)
  1027. poly[0] := Sqr(localRayStart.X) + hconst *
  1028. Sqr(localRayStart.Y - 0.5 * FHeight) +
  1029. Sqr(localRayStart.Z);
  1030. poly[1] := 2 * (localRayStart.X * localRayVector.X + hconst *
  1031. (localRayStart.Y - 0.5 * FHeight) * localRayVector.Y +
  1032. localRayStart.Z* localRayVector.Z);
  1033. poly[2] := Sqr(localRayVector.X) + hconst * Sqr(localRayVector.Y) +
  1034. Sqr(localRayVector.Z);
  1035. SetLength(roots, 0);
  1036. roots := SolveQuadric(@poly);
  1037. if MinPositiveCoef(roots, minRoot) then
  1038. begin
  1039. t := minRoot;
  1040. ip := VectorCombine(localRayStart, localRayVector, 1, t);
  1041. // check that intersection with infinite cone is within the range we want
  1042. if (ip.Y > -FHeight * 0.5) and (ip.Y < FHeight * 0.5) then
  1043. begin
  1044. Result := true;
  1045. if Assigned(intersectPoint) then
  1046. intersectPoint^ := LocalToAbsolute(ip);
  1047. if Assigned(intersectNormal) then
  1048. begin
  1049. ip.Y := hconst * (ip.Y - 0.5 * Height);
  1050. ip.W := 0;
  1051. NormalizeVector(ip);
  1052. intersectNormal^ := LocalToAbsolute(ip);
  1053. end;
  1054. end;
  1055. end;
  1056. end;
  1057. end;
  1058. // ------------------
  1059. // ------------------ TGLCylinder ------------------
  1060. // ------------------
  1061. constructor TGLCylinder.Create(AOwner: TComponent);
  1062. begin
  1063. inherited Create(AOwner);
  1064. FTopRadius := 0.5;
  1065. FParts := [cySides, cyBottom, cyTop];
  1066. FAlignment := caCenter;
  1067. end;
  1068. procedure TGLCylinder.BuildList(var rci: TGLRenderContextInfo);
  1069. var
  1070. quadric: PGLUquadricObj;
  1071. begin
  1072. gl.PushMatrix;
  1073. quadric := gluNewQuadric;
  1074. SetupQuadricParams(quadric);
  1075. gl.Rotatef(-90, 1, 0, 0);
  1076. case Alignment of
  1077. caTop:
  1078. gl.Translatef(0, 0, -FHeight);
  1079. caBottom:
  1080. ;
  1081. else // caCenter
  1082. gl.Translatef(0, 0, -FHeight * 0.5);
  1083. end;
  1084. if cySides in FParts then
  1085. gluCylinder(quadric, FBottomRadius, FTopRadius, FHeight, FSlices, FStacks);
  1086. if cyTop in FParts then
  1087. begin
  1088. gl.PushMatrix;
  1089. gl.Translatef(0, 0, FHeight);
  1090. gluDisk(Quadric, 0, FTopRadius, FSlices, FLoops);
  1091. gl.PopMatrix;
  1092. end;
  1093. if cyBottom in FParts then
  1094. begin
  1095. // swap quadric orientation because top of a disk is defined as outside
  1096. SetInvertedQuadricOrientation(quadric);
  1097. gluDisk(quadric, 0, FBottomRadius, FSlices, FLoops);
  1098. end;
  1099. gluDeleteQuadric(Quadric);
  1100. gl.PopMatrix;
  1101. end;
  1102. procedure TGLCylinder.SetTopRadius(const aValue: Single);
  1103. begin
  1104. if aValue <> FTopRadius then
  1105. begin
  1106. FTopRadius := aValue;
  1107. StructureChanged;
  1108. end;
  1109. end;
  1110. function TGLCylinder.GetTopRadius: Single;
  1111. begin
  1112. Result := FTopRadius;
  1113. end;
  1114. procedure TGLCylinder.SetParts(aValue: TGLCylinderParts);
  1115. begin
  1116. if aValue <> FParts then
  1117. begin
  1118. FParts := aValue;
  1119. StructureChanged;
  1120. end;
  1121. end;
  1122. procedure TGLCylinder.SetAlignment(val: TGLCylinderAlignment);
  1123. begin
  1124. if val <> FAlignment then
  1125. begin
  1126. FAlignment := val;
  1127. StructureChanged;
  1128. end;
  1129. end;
  1130. procedure TGLCylinder.Assign(Source: TPersistent);
  1131. begin
  1132. if Assigned(Source) and (Source is TGLCylinder) then
  1133. begin
  1134. FParts := TGLCylinder(Source).FParts;
  1135. FTopRadius := TGLCylinder(Source).FTopRadius;
  1136. end;
  1137. inherited Assign(Source);
  1138. end;
  1139. function TGLCylinder.AxisAlignedDimensionsUnscaled: TGLVector;
  1140. var
  1141. r, r1: Single;
  1142. begin
  1143. r := Abs(FBottomRadius);
  1144. r1 := Abs(FTopRadius);
  1145. if r1 > r then
  1146. r := r1;
  1147. Result := VectorMake(r, 0.5 * FHeight, r);
  1148. // ScaleVector(Result, Scale.AsVector);
  1149. end;
  1150. function TGLCylinder.RayCastIntersect(const rayStart, rayVector: TGLVector;
  1151. intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil): Boolean;
  1152. const
  1153. cOne: Single = 1;
  1154. var
  1155. locRayStart, locRayVector, ip: TGLVector;
  1156. poly: array [0 .. 2] of Double;
  1157. roots: TDoubleArray;
  1158. minRoot: Double;
  1159. t, tr2, invRayVector1, hTop, hBottom: Single;
  1160. tPlaneMin, tPlaneMax: Single;
  1161. begin
  1162. Result := False;
  1163. locRayStart := AbsoluteToLocal(rayStart);
  1164. locRayVector := AbsoluteToLocal(rayVector);
  1165. case Alignment of
  1166. caTop:
  1167. begin
  1168. hTop := 0;
  1169. hBottom := -Height;
  1170. end;
  1171. caBottom:
  1172. begin
  1173. hTop := Height;
  1174. hBottom := 0;
  1175. end;
  1176. else
  1177. // caCenter
  1178. hTop := Height * 0.5;
  1179. hBottom := -hTop;
  1180. end;
  1181. if locRayVector.Y = 0 then
  1182. begin
  1183. // intersect if ray shot through the top/bottom planes
  1184. if (locRayStart.X > hTop) or (locRayStart.X < hBottom) then
  1185. Exit;
  1186. tPlaneMin := -1E99;
  1187. tPlaneMax := 1E99;
  1188. end
  1189. else
  1190. begin
  1191. invRayVector1 := cOne / locRayVector.Y;
  1192. tr2 := Sqr(TopRadius);
  1193. // compute intersection with topPlane
  1194. t := (hTop - locRayStart.Y) * invRayVector1;
  1195. if (t > 0) and (cyTop in Parts) then
  1196. begin
  1197. ip.X := locRayStart.X + t * locRayVector.X;
  1198. ip.Z := locRayStart.Z + t * locRayVector.Z;
  1199. if Sqr(ip.X) + Sqr(ip.Z) <= tr2 then
  1200. begin
  1201. // intersect with top plane
  1202. if Assigned(intersectPoint) then
  1203. intersectPoint^ := LocalToAbsolute(VectorMake(ip.X, hTop, ip.Z, 1));
  1204. if Assigned(intersectNormal) then
  1205. intersectNormal^ := LocalToAbsolute(YHmgVector);
  1206. Result := true;
  1207. end;
  1208. end;
  1209. tPlaneMin := t;
  1210. tPlaneMax := t;
  1211. // compute intersection with bottomPlane
  1212. t := (hBottom - locRayStart.Y) * invRayVector1;
  1213. if (t > 0) and (cyBottom in Parts) then
  1214. begin
  1215. ip.X := locRayStart.X + t * locRayVector.X;
  1216. ip.Z := locRayStart.Z + t * locRayVector.Z;
  1217. if (t < tPlaneMin) or (not(cyTop in Parts)) then
  1218. begin
  1219. if Sqr(ip.X) + Sqr(ip.Z) <= tr2 then
  1220. begin
  1221. // intersect with top plane
  1222. if Assigned(intersectPoint) then
  1223. intersectPoint^ := LocalToAbsolute(VectorMake(ip.X, hBottom,
  1224. ip.Z, 1));
  1225. if Assigned(intersectNormal) then
  1226. intersectNormal^ := LocalToAbsolute(VectorNegate(YHmgVector));
  1227. Result := true;
  1228. end;
  1229. end;
  1230. end;
  1231. if t < tPlaneMin then
  1232. tPlaneMin := t;
  1233. if t > tPlaneMax then
  1234. tPlaneMax := t;
  1235. end;
  1236. if cySides in Parts then
  1237. begin
  1238. // intersect against cylinder infinite cylinder
  1239. poly[0] := Sqr(locRayStart.X) + Sqr(locRayStart.Z) - Sqr(TopRadius);
  1240. poly[1] := 2 * (locRayStart.X * locRayVector.X + locRayStart.Z *
  1241. locRayVector.Z);
  1242. poly[2] := Sqr(locRayVector.X) + Sqr(locRayVector.Z);
  1243. roots := SolveQuadric(@poly);
  1244. if MinPositiveCoef(roots, minRoot) then
  1245. begin
  1246. t := minRoot;
  1247. if (t >= tPlaneMin) and (t < tPlaneMax) then
  1248. begin
  1249. if Assigned(intersectPoint) or Assigned(intersectNormal) then
  1250. begin
  1251. ip := VectorCombine(locRayStart, locRayVector, 1, t);
  1252. if Assigned(intersectPoint) then
  1253. intersectPoint^ := LocalToAbsolute(ip);
  1254. if Assigned(intersectNormal) then
  1255. begin
  1256. ip.Y := 0;
  1257. ip.W := 0;
  1258. intersectNormal^ := LocalToAbsolute(ip);
  1259. end;
  1260. end;
  1261. Result := true;
  1262. end;
  1263. end;
  1264. end
  1265. else
  1266. SetLength(roots, 0);
  1267. end;
  1268. procedure TGLCylinder.Align(const startPoint, endPoint: TGLVector);
  1269. var
  1270. dir: TAffineVector;
  1271. begin
  1272. AbsolutePosition := startPoint;
  1273. VectorSubtract(endPoint, startPoint, dir);
  1274. if Parent <> nil then
  1275. dir := Parent.AbsoluteToLocal(dir);
  1276. Up.AsAffineVector := dir;
  1277. Height := VectorLength(dir);
  1278. Lift(Height * 0.5);
  1279. Alignment := caCenter;
  1280. end;
  1281. procedure TGLCylinder.Align(const startObj, endObj: TGLBaseSceneObject);
  1282. begin
  1283. Align(startObj.AbsolutePosition, endObj.AbsolutePosition);
  1284. end;
  1285. procedure TGLCylinder.Align(const startPoint, endPoint: TAffineVector);
  1286. begin
  1287. Align(PointMake(startPoint), PointMake(endPoint));
  1288. end;
  1289. // ------------------
  1290. // ------------------ TGLCapsule ------------------
  1291. // ------------------
  1292. constructor TGLCapsule.Create(AOwner: TComponent);
  1293. begin
  1294. inherited Create(AOwner);
  1295. FHeight := 1;
  1296. FRadius := 0.5;
  1297. FSlices := 4;
  1298. FStacks := 4;
  1299. FParts := [cySides, cyBottom, cyTop];
  1300. FAlignment := caCenter;
  1301. end;
  1302. procedure TGLCapsule.BuildList(var rci: TGLRenderContextInfo);
  1303. var
  1304. i, j, n: integer;
  1305. start_nx2: Single;
  1306. start_ny2: Single;
  1307. tmp, nx, ny, nz, start_nx, start_ny, a, ca, sa, l: Single;
  1308. nx2, ny2, nz2: Single;
  1309. begin
  1310. gl.PushMatrix;
  1311. gl.Rotatef(-90, 0, 0, 1);
  1312. case Alignment of
  1313. caTop:
  1314. gl.Translatef(0, 0, FHeight + 1);
  1315. caBottom:
  1316. gl.Translatef(0, 0, -FHeight);
  1317. else // caCenter
  1318. gl.Translatef(0, 0, 0.5);
  1319. end;
  1320. n := FSlices * FStacks;
  1321. l := FHeight;
  1322. l := l * 0.5;
  1323. a := (pi * 2.0) / n;
  1324. sa := sin(a);
  1325. ca := cos(a);
  1326. ny := 0;
  1327. nz := 1;
  1328. if cySides in FParts then
  1329. begin
  1330. gl.Begin_(GL_TRIANGLE_STRIP);
  1331. for i := 0 to n do
  1332. begin
  1333. gl.Normal3d(ny, nz, 0);
  1334. gl.TexCoord2f(i / n, 1);
  1335. gl.Vertex3d(ny * FRadius, nz * FRadius, l - 0.5);
  1336. gl.Normal3d(ny, nz, 0);
  1337. gl.TexCoord2f(i / n, 0);
  1338. gl.Vertex3d(ny * FRadius, nz * FRadius, -l - 0.5);
  1339. tmp := ca * ny - sa * nz;
  1340. nz := sa * ny + ca * nz;
  1341. ny := tmp;
  1342. end;
  1343. gl.End_();
  1344. end;
  1345. if cyTop in FParts then
  1346. begin
  1347. start_nx := 0;
  1348. start_ny := 1;
  1349. for j := 0 to (n div FStacks) do
  1350. begin
  1351. start_nx2 := ca * start_nx + sa * start_ny;
  1352. start_ny2 := -sa * start_nx + ca * start_ny;
  1353. nx := start_nx;
  1354. ny := start_ny;
  1355. nz := 0;
  1356. nx2 := start_nx2;
  1357. ny2 := start_ny2;
  1358. nz2 := 0;
  1359. gl.PushMatrix;
  1360. gl.Translatef(0, 0, -0.5);
  1361. gl.Begin_(GL_TRIANGLE_STRIP);
  1362. for i := 0 to n do
  1363. begin
  1364. gl.Normal3d(ny2, nz2, nx2);
  1365. gl.TexCoord2f(i / n, j / n);
  1366. gl.Vertex3d(ny2 * FRadius, nz2 * FRadius, l + nx2 * FRadius);
  1367. gl.Normal3d(ny, nz, nx);
  1368. gl.TexCoord2f(i / n, (j - 1) / n);
  1369. gl.Vertex3d(ny * FRadius, nz * FRadius, l + nx * FRadius);
  1370. tmp := ca * ny - sa * nz;
  1371. nz := sa * ny + ca * nz;
  1372. ny := tmp;
  1373. tmp := ca * ny2 - sa * nz2;
  1374. nz2 := sa * ny2 + ca * nz2;
  1375. ny2 := tmp;
  1376. end;
  1377. gl.End_();
  1378. gl.PopMatrix;
  1379. start_nx := start_nx2;
  1380. start_ny := start_ny2;
  1381. end;
  1382. end;
  1383. if cyBottom in FParts then
  1384. begin
  1385. start_nx := 0;
  1386. start_ny := 1;
  1387. for j := 0 to (n div FStacks) do
  1388. begin
  1389. start_nx2 := ca * start_nx - sa * start_ny;
  1390. start_ny2 := sa * start_nx + ca * start_ny;
  1391. nx := start_nx;
  1392. ny := start_ny;
  1393. nz := 0;
  1394. nx2 := start_nx2;
  1395. ny2 := start_ny2;
  1396. nz2 := 0;
  1397. gl.PushMatrix;
  1398. gl.Translatef(0, 0, -0.5);
  1399. gl.Begin_(GL_TRIANGLE_STRIP);
  1400. for i := 0 to n do
  1401. begin
  1402. gl.Normal3d(ny, nz, nx);
  1403. gl.TexCoord2f(i / n, (j - 1) / n);
  1404. gl.Vertex3d(ny * FRadius, nz * FRadius, -l + nx * FRadius);
  1405. gl.Normal3d(ny2, nz2, nx2);
  1406. gl.TexCoord2f(i / n, j / n);
  1407. gl.Vertex3d(ny2 * FRadius, nz2 * FRadius, -l + nx2 * FRadius);
  1408. tmp := ca * ny - sa * nz;
  1409. nz := sa * ny + ca * nz;
  1410. ny := tmp;
  1411. tmp := ca * ny2 - sa * nz2;
  1412. nz2 := sa * ny2 + ca * nz2;
  1413. ny2 := tmp;
  1414. end;
  1415. gl.End_();
  1416. gl.PopMatrix;
  1417. start_nx := start_nx2;
  1418. start_ny := start_ny2;
  1419. end;
  1420. end;
  1421. gl.PopMatrix;
  1422. end;
  1423. procedure TGLCapsule.SetHeight(const aValue: Single);
  1424. begin
  1425. if aValue <> FHeight then
  1426. begin
  1427. FHeight := aValue;
  1428. StructureChanged;
  1429. end;
  1430. end;
  1431. procedure TGLCapsule.SetRadius(const aValue: Single);
  1432. begin
  1433. if aValue <> FRadius then
  1434. begin
  1435. FRadius := aValue;
  1436. StructureChanged;
  1437. end;
  1438. end;
  1439. procedure TGLCapsule.SetSlices(const aValue: integer);
  1440. begin
  1441. if aValue <> FSlices then
  1442. begin
  1443. FSlices := aValue;
  1444. StructureChanged;
  1445. end;
  1446. end;
  1447. procedure TGLCapsule.SetStacks(const aValue: integer);
  1448. begin
  1449. if aValue <> FStacks then
  1450. begin
  1451. FStacks := aValue;
  1452. StructureChanged;
  1453. end;
  1454. end;
  1455. procedure TGLCapsule.SetParts(aValue: TGLCylinderParts);
  1456. begin
  1457. if aValue <> FParts then
  1458. begin
  1459. FParts := aValue;
  1460. StructureChanged;
  1461. end;
  1462. end;
  1463. procedure TGLCapsule.SetAlignment(val: TGLCylinderAlignment);
  1464. begin
  1465. if val <> FAlignment then
  1466. begin
  1467. FAlignment := val;
  1468. StructureChanged;
  1469. end;
  1470. end;
  1471. procedure TGLCapsule.Assign(Source: TPersistent);
  1472. begin
  1473. if Assigned(Source) and (Source is TGLCapsule) then
  1474. begin
  1475. FParts := TGLCapsule(Source).FParts;
  1476. FRadius := TGLCapsule(Source).FRadius;
  1477. end;
  1478. inherited Assign(Source);
  1479. end;
  1480. function TGLCapsule.AxisAlignedDimensionsUnscaled: TGLVector;
  1481. var
  1482. r, r1: Single;
  1483. begin
  1484. r := Abs(FRadius);
  1485. r1 := Abs(FRadius);
  1486. if r1 > r then
  1487. r := r1;
  1488. Result := VectorMake(r, 0.5 * FHeight, r);
  1489. // ScaleVector(Result, Scale.AsVector);
  1490. end;
  1491. function TGLCapsule.RayCastIntersect(const rayStart, rayVector: TGLVector;
  1492. intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil): Boolean;
  1493. const
  1494. cOne: Single = 1;
  1495. var
  1496. locRayStart, locRayVector, ip: TGLVector;
  1497. poly: array [0 .. 2] of Double;
  1498. roots: TDoubleArray;
  1499. minRoot: Double;
  1500. t, tr2, invRayVector1, hTop, hBottom: Single;
  1501. tPlaneMin, tPlaneMax: Single;
  1502. begin
  1503. Result := False;
  1504. locRayStart := AbsoluteToLocal(rayStart);
  1505. locRayVector := AbsoluteToLocal(rayVector);
  1506. case Alignment of
  1507. caTop:
  1508. begin
  1509. hTop := 0;
  1510. hBottom := -FHeight;
  1511. end;
  1512. caBottom:
  1513. begin
  1514. hTop := FHeight;
  1515. hBottom := 0;
  1516. end;
  1517. else
  1518. // caCenter
  1519. hTop := FHeight * 0.5;
  1520. hBottom := -hTop;
  1521. end;
  1522. if locRayVector.Y = 0 then
  1523. begin
  1524. // intersect if ray shot through the top/bottom planes
  1525. if (locRayStart.X > hTop) or (locRayStart.X < hBottom) then
  1526. Exit;
  1527. tPlaneMin := -1E99;
  1528. tPlaneMax := 1E99;
  1529. end
  1530. else
  1531. begin
  1532. invRayVector1 := cOne / locRayVector.Y;
  1533. tr2 := Sqr(Radius);
  1534. // compute intersection with topPlane
  1535. t := (hTop - locRayStart.Y) * invRayVector1;
  1536. if (t > 0) and (cyTop in Parts) then
  1537. begin
  1538. ip.X := locRayStart.X + t * locRayVector.X;
  1539. ip.Z := locRayStart.Z + t * locRayVector.Z;
  1540. if Sqr(ip.X) + Sqr(ip.Z) <= tr2 then
  1541. begin
  1542. // intersect with top plane
  1543. if Assigned(intersectPoint) then
  1544. intersectPoint^ := LocalToAbsolute(VectorMake(ip.X, hTop, ip.Z, 1));
  1545. if Assigned(intersectNormal) then
  1546. intersectNormal^ := LocalToAbsolute(YHmgVector);
  1547. Result := true;
  1548. end;
  1549. end;
  1550. tPlaneMin := t;
  1551. tPlaneMax := t;
  1552. // compute intersection with bottomPlane
  1553. t := (hBottom - locRayStart.Y) * invRayVector1;
  1554. if (t > 0) and (cyBottom in Parts) then
  1555. begin
  1556. ip.X := locRayStart.X + t * locRayVector.X;
  1557. ip.Z := locRayStart.Z + t * locRayVector.Z;
  1558. if (t < tPlaneMin) or (not(cyTop in Parts)) then
  1559. begin
  1560. if Sqr(ip.X) + Sqr(ip.Z) <= tr2 then
  1561. begin
  1562. // intersect with top plane
  1563. if Assigned(intersectPoint) then
  1564. intersectPoint^ := LocalToAbsolute(VectorMake(ip.X, hBottom,
  1565. ip.Z, 1));
  1566. if Assigned(intersectNormal) then
  1567. intersectNormal^ := LocalToAbsolute(VectorNegate(YHmgVector));
  1568. Result := true;
  1569. end;
  1570. end;
  1571. end;
  1572. if t < tPlaneMin then
  1573. tPlaneMin := t;
  1574. if t > tPlaneMax then
  1575. tPlaneMax := t;
  1576. end;
  1577. if cySides in Parts then
  1578. begin
  1579. // intersect against cylinder infinite cylinder
  1580. poly[0] := Sqr(locRayStart.X) + Sqr(locRayStart.Z) - Sqr(Radius);
  1581. poly[1] := 2 * (locRayStart.X * locRayVector.X +
  1582. locRayStart.Z * locRayVector.Z);
  1583. poly[2] := Sqr(locRayVector.X) + Sqr(locRayVector.Z);
  1584. roots := SolveQuadric(@poly);
  1585. if MinPositiveCoef(roots, minRoot) then
  1586. begin
  1587. t := minRoot;
  1588. if (t >= tPlaneMin) and (t < tPlaneMax) then
  1589. begin
  1590. if Assigned(intersectPoint) or Assigned(intersectNormal) then
  1591. begin
  1592. ip := VectorCombine(locRayStart, locRayVector, 1, t);
  1593. if Assigned(intersectPoint) then
  1594. intersectPoint^ := LocalToAbsolute(ip);
  1595. if Assigned(intersectNormal) then
  1596. begin
  1597. ip.Y := 0;
  1598. ip.W := 0;
  1599. intersectNormal^ := LocalToAbsolute(ip);
  1600. end;
  1601. end;
  1602. Result := true;
  1603. end;
  1604. end;
  1605. end
  1606. else
  1607. SetLength(roots, 0);
  1608. end;
  1609. procedure TGLCapsule.Align(const startPoint, endPoint: TGLVector);
  1610. var
  1611. dir: TAffineVector;
  1612. begin
  1613. AbsolutePosition := startPoint;
  1614. VectorSubtract(endPoint, startPoint, dir);
  1615. if Parent <> nil then
  1616. dir := Parent.AbsoluteToLocal(dir);
  1617. Up.AsAffineVector := dir;
  1618. FHeight := VectorLength(dir);
  1619. Lift(FHeight * 0.5);
  1620. Alignment := caCenter;
  1621. end;
  1622. procedure TGLCapsule.Align(const startObj, endObj: TGLBaseSceneObject);
  1623. begin
  1624. Align(startObj.AbsolutePosition, endObj.AbsolutePosition);
  1625. end;
  1626. procedure TGLCapsule.Align(const startPoint, endPoint: TAffineVector);
  1627. begin
  1628. Align(PointMake(startPoint), PointMake(endPoint));
  1629. end;
  1630. // ------------------
  1631. // ------------------ TGLAnnulus ------------------
  1632. // ------------------
  1633. constructor TGLAnnulus.Create(AOwner: TComponent);
  1634. begin
  1635. inherited Create(AOwner);
  1636. FBottomInnerRadius := 0.3;
  1637. FTopInnerRadius := 0.3;
  1638. FTopRadius := 0.5;
  1639. FParts := [anInnerSides, anOuterSides, anBottom, anTop];
  1640. end;
  1641. procedure TGLAnnulus.SetBottomInnerRadius(const aValue: Single);
  1642. begin
  1643. if aValue <> FBottomInnerRadius then
  1644. begin
  1645. FBottomInnerRadius := aValue;
  1646. StructureChanged;
  1647. end;
  1648. end;
  1649. procedure TGLAnnulus.SetTopRadius(const aValue: Single);
  1650. begin
  1651. if aValue <> FTopRadius then
  1652. begin
  1653. FTopRadius := aValue;
  1654. StructureChanged;
  1655. end;
  1656. end;
  1657. procedure TGLAnnulus.SetTopInnerRadius(const aValue: Single);
  1658. begin
  1659. if aValue <> FTopInnerRadius then
  1660. begin
  1661. FTopInnerRadius := aValue;
  1662. StructureChanged;
  1663. end;
  1664. end;
  1665. procedure TGLAnnulus.SetParts(aValue: TGLAnnulusParts);
  1666. begin
  1667. if aValue <> FParts then
  1668. begin
  1669. FParts := aValue;
  1670. StructureChanged;
  1671. end;
  1672. end;
  1673. procedure TGLAnnulus.BuildList(var rci: TGLRenderContextInfo);
  1674. var
  1675. quadric: PGLUquadricObj;
  1676. begin
  1677. gl.PushMatrix;
  1678. quadric := gluNewQuadric;
  1679. SetupQuadricParams(quadric);
  1680. gl.Rotatef(-90, 1, 0, 0);
  1681. gl.Translatef(0, 0, -FHeight * 0.5);
  1682. if anOuterSides in FParts then
  1683. gluCylinder(quadric, FBottomRadius, FTopRadius, FHeight, FSlices, FStacks);
  1684. if anTop in FParts then
  1685. begin
  1686. gl.PushMatrix;
  1687. gl.Translatef(0, 0, FHeight);
  1688. gluDisk(quadric, FTopInnerRadius, FTopRadius, FSlices, FLoops);
  1689. gl.PopMatrix;
  1690. end;
  1691. if [anBottom, anInnerSides] * FParts <> [] then
  1692. begin
  1693. // swap quadric orientation because top of a disk is defined as outside
  1694. SetInvertedQuadricOrientation(quadric);
  1695. if anBottom in FParts then
  1696. gluDisk(quadric, FBottomInnerRadius, FBottomRadius, FSlices, FLoops);
  1697. if anInnerSides in FParts then
  1698. gluCylinder(quadric, FBottomInnerRadius, FTopInnerRadius, FHeight,
  1699. FSlices, FStacks);
  1700. end;
  1701. gluDeleteQuadric(quadric);
  1702. gl.PopMatrix;
  1703. end;
  1704. procedure TGLAnnulus.Assign(Source: TPersistent);
  1705. begin
  1706. if Assigned(Source) and (Source is TGLAnnulus) then
  1707. begin
  1708. FParts := TGLAnnulus(Source).FParts;
  1709. FTopRadius := TGLAnnulus(Source).FTopRadius;
  1710. FTopInnerRadius := TGLAnnulus(Source).FTopInnerRadius;
  1711. FBottomRadius := TGLAnnulus(Source).FBottomRadius;
  1712. FBottomInnerRadius := TGLAnnulus(Source).FBottomInnerRadius;
  1713. end;
  1714. inherited Assign(Source);
  1715. end;
  1716. function TGLAnnulus.AxisAlignedDimensionsUnscaled: TGLVector;
  1717. var
  1718. r, r1: Single;
  1719. begin
  1720. r := Abs(FBottomRadius);
  1721. r1 := Abs(FTopRadius);
  1722. if r1 > r then
  1723. r := r1;
  1724. Result := VectorMake(r, 0.5 * FHeight, r);
  1725. end;
  1726. function TGLAnnulus.RayCastIntersect(const rayStart, rayVector: TGLVector;
  1727. intersectPoint, intersectNormal: PGLVector): Boolean;
  1728. const
  1729. cOne: Single = 1;
  1730. var
  1731. locRayStart, locRayVector, ip: TGLVector;
  1732. poly: array [0 .. 2] of Double;
  1733. t, tr2, invRayVector1: Single;
  1734. tPlaneMin, tPlaneMax: Single;
  1735. tir2, d2: Single;
  1736. Root: Double;
  1737. roots, tmpRoots: TDoubleArray;
  1738. FirstIntersected: Boolean;
  1739. h1, h2, hTop, hBot: Single;
  1740. Draw1, Draw2: Boolean;
  1741. begin
  1742. Result := False;
  1743. FirstIntersected := False;
  1744. SetLength(tmpRoots, 0);
  1745. locRayStart := AbsoluteToLocal(rayStart);
  1746. locRayVector := AbsoluteToLocal(rayVector);
  1747. hTop := Height * 0.5;
  1748. hBot := -hTop;
  1749. if locRayVector.Y < 0 then
  1750. begin // Sort the planes according to the direction of view
  1751. h1 := hTop; // Height of the 1st plane
  1752. h2 := hBot; // Height of the 2nd plane
  1753. Draw1 := (anTop in Parts); // 1st "cap" Must be drawn?
  1754. Draw2 := (anBottom in Parts);
  1755. end
  1756. else
  1757. begin
  1758. h1 := hBot;
  1759. h2 := hTop;
  1760. Draw1 := (anBottom in Parts);
  1761. Draw2 := (anTop in Parts);
  1762. end; // if
  1763. if locRayVector.Y = 0 then
  1764. begin
  1765. // intersect if ray shot through the top/bottom planes
  1766. if (locRayStart.X > hTop) or (locRayStart.X < hBot) then
  1767. Exit;
  1768. tPlaneMin := -1E99;
  1769. tPlaneMax := 1E99;
  1770. end
  1771. else
  1772. begin
  1773. invRayVector1 := cOne / locRayVector.Y;
  1774. tr2 := Sqr(TopRadius);
  1775. tir2 := Sqr(TopInnerRadius);
  1776. FirstIntersected := False;
  1777. // compute intersection with first plane
  1778. t := (h1 - locRayStart.Y) * invRayVector1;
  1779. if (t > 0) and Draw1 then
  1780. begin
  1781. ip.X := locRayStart.X + t * locRayVector.X;
  1782. ip.Z := locRayStart.Z + t * locRayVector.Z;
  1783. d2 := Sqr(ip.X) + Sqr(ip.Z);
  1784. if (d2 <= tr2) and (d2 >= tir2) then
  1785. begin
  1786. // intersect with top plane
  1787. FirstIntersected := true;
  1788. if Assigned(intersectPoint) then
  1789. intersectPoint^ := LocalToAbsolute(VectorMake(ip.X, h1, ip.Z, 1));
  1790. if Assigned(intersectNormal) then
  1791. intersectNormal^ := LocalToAbsolute(YHmgVector);
  1792. Result := true;
  1793. end;
  1794. end;
  1795. tPlaneMin := t;
  1796. tPlaneMax := t;
  1797. // compute intersection with second plane
  1798. t := (h2 - locRayStart.Y) * invRayVector1;
  1799. if (t > 0) and Draw2 then
  1800. begin
  1801. ip.X := locRayStart.X + t * locRayVector.X;
  1802. ip.Z := locRayStart.Z + t * locRayVector.Z;
  1803. d2 := Sqr(ip.X) + Sqr(ip.Z);
  1804. if (t < tPlaneMin) or (not FirstIntersected) then
  1805. begin
  1806. if (d2 <= tr2) and (d2 >= tir2) then
  1807. begin
  1808. // intersect with top plane
  1809. if Assigned(intersectPoint) then
  1810. intersectPoint^ := LocalToAbsolute(VectorMake(ip.X, h2, ip.Z, 1));
  1811. if Assigned(intersectNormal) then
  1812. intersectNormal^ := LocalToAbsolute(VectorNegate(YHmgVector));
  1813. Result := true;
  1814. end;
  1815. end;
  1816. end;
  1817. if t < tPlaneMin then
  1818. begin
  1819. tPlaneMin := t;
  1820. end; // if
  1821. if t > tPlaneMax then
  1822. tPlaneMax := t;
  1823. end;
  1824. try
  1825. SetLength(roots, 4);
  1826. roots[0] := -1;
  1827. roots[1] := -1;
  1828. roots[2] := -1;
  1829. roots[3] := -1; // By default, side is behind rayStart
  1830. // Compute roots for outer cylinder
  1831. if anOuterSides in Parts then
  1832. begin
  1833. // intersect against infinite cylinder, will be cut by tPlaneMine and tPlaneMax
  1834. poly[0] := Sqr(locRayStart.X) + Sqr(locRayStart.Z) - Sqr(TopRadius);
  1835. poly[1] := 2 * (locRayStart.X * locRayVector.X + locRayStart.Z *
  1836. locRayVector.Z);
  1837. poly[2] := Sqr(locRayVector.X) + Sqr(locRayVector.Z);
  1838. tmpRoots := SolveQuadric(@poly);
  1839. // Intersect coordinates on rayVector (rayStart=0)
  1840. if ( High(tmpRoots) >= 0) and // Does root exist?
  1841. ((tmpRoots[0] > tPlaneMin) and not FirstIntersected) and
  1842. // In the annulus and not masked by first cap
  1843. ((tmpRoots[0] < tPlaneMax)) { // In the annulus } then
  1844. roots[0] := tmpRoots[0];
  1845. if ( High(tmpRoots) >= 1) and
  1846. ((tmpRoots[1] > tPlaneMin) and not FirstIntersected) and
  1847. ((tmpRoots[1] < tPlaneMax)) then
  1848. roots[1] := tmpRoots[1];
  1849. end; // if
  1850. // Compute roots for inner cylinder
  1851. if anInnerSides in Parts then
  1852. begin
  1853. // intersect against infinite cylinder
  1854. poly[0] := Sqr(locRayStart.X) +
  1855. Sqr(locRayStart.Z) - Sqr(TopInnerRadius);
  1856. poly[1] := 2 * (locRayStart.X * locRayVector.X +
  1857. locRayStart.Z * locRayVector.Z);
  1858. poly[2] := Sqr(locRayVector.X) + Sqr(locRayVector.Z);
  1859. tmpRoots := SolveQuadric(@poly);
  1860. if ( High(tmpRoots) >= 0) and
  1861. ((tmpRoots[0] > tPlaneMin) and not FirstIntersected) and
  1862. ((tmpRoots[0] < tPlaneMax)) then
  1863. roots[2] := tmpRoots[0];
  1864. if ( High(tmpRoots) >= 1) and
  1865. ((tmpRoots[1] > tPlaneMin) and not FirstIntersected) and
  1866. ((tmpRoots[1] < tPlaneMax)) then
  1867. roots[3] := tmpRoots[1];
  1868. end; // if
  1869. // Find the first intersection point and compute its coordinates and normal
  1870. if MinPositiveCoef(roots, Root) then
  1871. begin
  1872. t := Root;
  1873. if (t >= tPlaneMin) and (t < tPlaneMax) then
  1874. begin
  1875. if Assigned(intersectPoint) or Assigned(intersectNormal) then
  1876. begin
  1877. ip := VectorCombine(locRayStart, locRayVector, 1, t);
  1878. if Assigned(intersectPoint) then
  1879. intersectPoint^ := LocalToAbsolute(ip);
  1880. if Assigned(intersectNormal) then
  1881. begin
  1882. ip.Y := 0;
  1883. ip.W := 0;
  1884. intersectNormal^ := LocalToAbsolute(ip);
  1885. end;
  1886. end;
  1887. Result := true;
  1888. end;
  1889. end;
  1890. finally
  1891. roots := nil;
  1892. tmpRoots := nil;
  1893. end; // finally
  1894. end;
  1895. // ------------------
  1896. // ------------------ TGLTorus ------------------
  1897. // ------------------
  1898. constructor TGLTorus.Create(AOwner: TComponent);
  1899. begin
  1900. inherited Create(AOwner);
  1901. FRings := 25;
  1902. FSides := 15;
  1903. FMinorRadius := 0.1;
  1904. FMajorRadius := 0.4;
  1905. FStartAngle := 0.0;
  1906. FStopAngle := 360.0;
  1907. FParts := [toSides, toStartDisk, toStopDisk];
  1908. end;
  1909. procedure TGLTorus.BuildList(var rci: TGLRenderContextInfo);
  1910. procedure EmitVertex(ptr: PGLVertexRec; L1, L2: integer);
  1911. begin
  1912. XGL.TexCoord2fv(@ptr^.TexCoord);
  1913. begin
  1914. gl.Normal3fv(@ptr^.Normal);
  1915. if L1 > -1 then
  1916. gl.VertexAttrib3fv(L1, @ptr.Tangent);
  1917. if L2 > -1 then
  1918. gl.VertexAttrib3fv(L2, @ptr.Binormal);
  1919. gl.Vertex3fv(@ptr^.Position);
  1920. end;
  1921. end;
  1922. var
  1923. i, j: integer;
  1924. Theta, Phi, Theta1, cosPhi, sinPhi, dist: Single;
  1925. cosTheta1, sinTheta1: Single;
  1926. ringDelta, sideDelta: Single;
  1927. ringDir: TAffineVector;
  1928. iFact, jFact: Single;
  1929. pVertex: PGLVertexRec;
  1930. TanLoc, BinLoc: Integer;
  1931. MeshSize: integer;
  1932. MeshIndex: integer;
  1933. Vertex: TGLVertexRec;
  1934. begin
  1935. if FMesh = nil then
  1936. begin
  1937. MeshSize := 0;
  1938. MeshIndex := 0;
  1939. if toStartDisk in FParts then
  1940. MeshSize := MeshSize + 1;
  1941. if toStopDisk in FParts then
  1942. MeshSize := MeshSize + 1;
  1943. if toSides in FParts then
  1944. MeshSize := MeshSize + Integer(FRings) + 1;
  1945. SetLength(FMesh, MeshSize);
  1946. // handle texture generation
  1947. ringDelta := ((FStopAngle - FStartAngle) / 360) * c2PI / FRings;
  1948. sideDelta := c2PI / FSides;
  1949. iFact := 1 / FRings;
  1950. jFact := 1 / FSides;
  1951. if toSides in FParts then
  1952. begin
  1953. Theta := DegToRadian(FStartAngle) - ringDelta;
  1954. for i := FRings downto 0 do
  1955. begin
  1956. SetLength(FMesh[i], FSides + 1);
  1957. Theta1 := Theta + ringDelta;
  1958. SinCosine(Theta1, sinTheta1, cosTheta1);
  1959. Phi := 0;
  1960. for j := FSides downto 0 do
  1961. begin
  1962. Phi := Phi + sideDelta;
  1963. SinCosine(Phi, sinPhi, cosPhi);
  1964. dist := FMajorRadius + FMinorRadius * cosPhi;
  1965. FMesh[i][j].Position := Vector3fMake(cosTheta1 * dist,
  1966. -sinTheta1 * dist, FMinorRadius * sinPhi);
  1967. ringDir := FMesh[i][j].Position;
  1968. ringDir.Z := 0.0;
  1969. NormalizeVector(ringDir);
  1970. FMesh[i][j].Normal := Vector3fMake(cosTheta1 * cosPhi,
  1971. -sinTheta1 * cosPhi, sinPhi);
  1972. FMesh[i][j].Tangent := VectorCrossProduct(ZVector, ringDir);
  1973. FMesh[i][j].Binormal := VectorCrossProduct(FMesh[i][j].Normal,
  1974. FMesh[i][j].Tangent);
  1975. FMesh[i][j].TexCoord := Vector2fMake(i * iFact, j * jFact);
  1976. end;
  1977. Theta := Theta1;
  1978. end;
  1979. MeshIndex := FRings + 1;
  1980. end;
  1981. if toStartDisk in FParts then
  1982. begin
  1983. SetLength(FMesh[MeshIndex], FSides + 1);
  1984. Theta1 := DegToRadian(FStartAngle);
  1985. SinCosine(Theta1, sinTheta1, cosTheta1);
  1986. if toSides in FParts then
  1987. begin
  1988. for j := FSides downto 0 do
  1989. begin
  1990. FMesh[MeshIndex][j].Position := FMesh[MeshIndex - 1][j].Position;
  1991. FMesh[MeshIndex][j].Normal := FMesh[MeshIndex - 1][j].Tangent;
  1992. FMesh[MeshIndex][j].Tangent := FMesh[MeshIndex - 1][j].Position;
  1993. FMesh[MeshIndex][j].Tangent.Z := 0;
  1994. FMesh[MeshIndex][j].Binormal := ZVector;
  1995. FMesh[MeshIndex][j].TexCoord := FMesh[MeshIndex - 1][j].TexCoord;
  1996. FMesh[MeshIndex][j].TexCoord.X := 0;
  1997. end;
  1998. end
  1999. else
  2000. begin
  2001. Phi := 0;
  2002. for j := FSides downto 0 do
  2003. begin
  2004. Phi := Phi + sideDelta;
  2005. SinCosine(Phi, sinPhi, cosPhi);
  2006. dist := FMajorRadius + FMinorRadius * cosPhi;
  2007. FMesh[MeshIndex][j].Position := Vector3fMake(cosTheta1 * dist,
  2008. -sinTheta1 * dist, FMinorRadius * sinPhi);
  2009. ringDir := FMesh[MeshIndex][j].Position;
  2010. ringDir.Z := 0.0;
  2011. NormalizeVector(ringDir);
  2012. FMesh[MeshIndex][j].Normal := VectorCrossProduct(ZVector, ringDir);
  2013. FMesh[MeshIndex][j].Tangent := ringDir;
  2014. FMesh[MeshIndex][j].Binormal := ZVector;
  2015. FMesh[MeshIndex][j].TexCoord := Vector2fMake(0, j * jFact);
  2016. end;
  2017. end;
  2018. Vertex.Position := Vector3fMake(cosTheta1 * FMajorRadius,
  2019. -sinTheta1 * FMajorRadius, 0);
  2020. Vertex.Normal := FMesh[MeshIndex][0].Normal;
  2021. Vertex.Tangent := FMesh[MeshIndex][0].Tangent;
  2022. Vertex.Binormal := FMesh[MeshIndex][0].Binormal;
  2023. Vertex.TexCoord := Vector2fMake(1, 1);
  2024. MeshIndex := MeshIndex + 1;
  2025. end;
  2026. if toStopDisk in FParts then
  2027. begin
  2028. SetLength(FMesh[MeshIndex], FSides + 1);
  2029. Theta1 := DegToRadian(FStopAngle);
  2030. SinCosine(Theta1, sinTheta1, cosTheta1);
  2031. if toSides in FParts then
  2032. begin
  2033. for j := FSides downto 0 do
  2034. begin
  2035. FMesh[MeshIndex][j].Position := FMesh[0][j].Position;
  2036. FMesh[MeshIndex][j].Normal := VectorNegate(FMesh[0][j].Tangent);
  2037. FMesh[MeshIndex][j].Tangent := FMesh[0][j].Position;
  2038. FMesh[MeshIndex][j].Tangent.Z := 0;
  2039. FMesh[MeshIndex][j].Binormal := VectorNegate(ZVector);
  2040. FMesh[MeshIndex][j].TexCoord := FMesh[0][j].TexCoord;
  2041. FMesh[MeshIndex][j].TexCoord.X := 1;
  2042. end;
  2043. end
  2044. else
  2045. begin
  2046. Phi := 0;
  2047. for j := FSides downto 0 do
  2048. begin
  2049. Phi := Phi + sideDelta;
  2050. SinCosine(Phi, sinPhi, cosPhi);
  2051. dist := FMajorRadius + FMinorRadius * cosPhi;
  2052. FMesh[MeshIndex][j].Position := Vector3fMake(cosTheta1 * dist,
  2053. -sinTheta1 * dist, FMinorRadius * sinPhi);
  2054. ringDir := FMesh[MeshIndex][j].Position;
  2055. ringDir.Z := 0.0;
  2056. NormalizeVector(ringDir);
  2057. FMesh[MeshIndex][j].Normal := VectorCrossProduct(ringDir, ZVector);
  2058. FMesh[MeshIndex][j].Tangent := ringDir;
  2059. FMesh[MeshIndex][j].Binormal := VectorNegate(ZVector);
  2060. FMesh[MeshIndex][j].TexCoord := Vector2fMake(1, j * jFact);
  2061. end;
  2062. end;
  2063. Vertex.Position := Vector3fMake(cosTheta1 * FMajorRadius,
  2064. -sinTheta1 * FMajorRadius, 0);
  2065. Vertex.Normal := FMesh[MeshIndex][0].Normal;
  2066. Vertex.Tangent := FMesh[MeshIndex][0].Tangent;
  2067. Vertex.Binormal := FMesh[MeshIndex][0].Binormal;
  2068. Vertex.TexCoord := Vector2fMake(0, 0);
  2069. end;
  2070. end;
  2071. begin
  2072. if GL.ARB_shader_objects and (rci.GLStates.CurrentProgram > 0) then
  2073. begin
  2074. TanLoc := gl.GetAttribLocation(rci.GLStates.CurrentProgram,
  2075. PAnsiChar(TangentAttributeName));
  2076. BinLoc := gl.GetAttribLocation(rci.GLStates.CurrentProgram,
  2077. PAnsiChar(BinormalAttributeName));
  2078. end
  2079. else
  2080. begin
  2081. TanLoc := -1;
  2082. BinLoc := TanLoc;
  2083. end;
  2084. MeshIndex := 0;
  2085. if toSides in FParts then
  2086. begin
  2087. gl.Begin_(GL_TRIANGLES);
  2088. for i := FRings - 1 downto 0 do
  2089. for j := FSides - 1 downto 0 do
  2090. begin
  2091. pVertex := @FMesh[i][j];
  2092. EmitVertex(pVertex, TanLoc, BinLoc);
  2093. pVertex := @FMesh[i][j + 1];
  2094. EmitVertex(pVertex, TanLoc, BinLoc);
  2095. pVertex := @FMesh[i + 1][j];
  2096. EmitVertex(pVertex, TanLoc, BinLoc);
  2097. pVertex := @FMesh[i + 1][j + 1];
  2098. EmitVertex(pVertex, TanLoc, BinLoc);
  2099. pVertex := @FMesh[i + 1][j];
  2100. EmitVertex(pVertex, TanLoc, BinLoc);
  2101. pVertex := @FMesh[i][j + 1];
  2102. EmitVertex(pVertex, TanLoc, BinLoc);
  2103. end;
  2104. gl.End_;
  2105. MeshIndex := FRings + 1;
  2106. end;
  2107. if toStartDisk in FParts then
  2108. begin
  2109. gl.Begin_(GL_TRIANGLE_FAN);
  2110. pVertex := @Vertex;
  2111. EmitVertex(pVertex, TanLoc, BinLoc);
  2112. for j := 0 to FSides do
  2113. begin
  2114. pVertex := @FMesh[MeshIndex][j];
  2115. EmitVertex(pVertex, TanLoc, BinLoc);
  2116. end;
  2117. gl.End_;
  2118. MeshIndex := MeshIndex + 1;
  2119. end;
  2120. if toStopDisk in FParts then
  2121. begin
  2122. gl.Begin_(GL_TRIANGLE_FAN);
  2123. pVertex := @Vertex;
  2124. EmitVertex(pVertex, TanLoc, BinLoc);
  2125. for j := FSides downto 0 do
  2126. begin
  2127. pVertex := @FMesh[MeshIndex][j];
  2128. EmitVertex(pVertex, TanLoc, BinLoc);
  2129. end;
  2130. gl.End_;
  2131. end;
  2132. end;
  2133. end;
  2134. procedure TGLTorus.SetMajorRadius(const aValue: Single);
  2135. begin
  2136. if FMajorRadius <> aValue then
  2137. begin
  2138. FMajorRadius := aValue;
  2139. FMesh := nil;
  2140. StructureChanged;
  2141. end;
  2142. end;
  2143. procedure TGLTorus.SetMinorRadius(const aValue: Single);
  2144. begin
  2145. if FMinorRadius <> aValue then
  2146. begin
  2147. FMinorRadius := aValue;
  2148. FMesh := nil;
  2149. StructureChanged;
  2150. end;
  2151. end;
  2152. procedure TGLTorus.SetRings(aValue: Cardinal);
  2153. begin
  2154. if FRings <> aValue then
  2155. begin
  2156. FRings := aValue;
  2157. if FRings < 2 then
  2158. FRings := 2;
  2159. FMesh := nil;
  2160. StructureChanged;
  2161. end;
  2162. end;
  2163. procedure TGLTorus.SetSides(aValue: Cardinal);
  2164. begin
  2165. if FSides <> aValue then
  2166. begin
  2167. FSides := aValue;
  2168. if FSides < 3 then
  2169. FSides := 3;
  2170. FMesh := nil;
  2171. StructureChanged;
  2172. end;
  2173. end;
  2174. procedure TGLTorus.SetStartAngle(const aValue: Single);
  2175. begin
  2176. if FStartAngle <> aValue then
  2177. begin
  2178. FStartAngle := aValue;
  2179. FMesh := nil;
  2180. StructureChanged;
  2181. end;
  2182. end;
  2183. procedure TGLTorus.SetStopAngle(const aValue: Single);
  2184. begin
  2185. if FStopAngle <> aValue then
  2186. begin
  2187. FStopAngle := aValue;
  2188. FMesh := nil;
  2189. StructureChanged;
  2190. end;
  2191. end;
  2192. procedure TGLTorus.SetParts(aValue: TGLTorusParts);
  2193. begin
  2194. if aValue <> FParts then
  2195. begin
  2196. FParts := aValue;
  2197. StructureChanged;
  2198. end;
  2199. end;
  2200. function TGLTorus.AxisAlignedDimensionsUnscaled: TGLVector;
  2201. var
  2202. r, r1: Single;
  2203. begin
  2204. r := Abs(FMajorRadius);
  2205. r1 := Abs(FMinorRadius);
  2206. Result := VectorMake(r + r1, r + r1, r1); // Danb
  2207. end;
  2208. function TGLTorus.RayCastIntersect(const rayStart, rayVector: TGLVector;
  2209. intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil): Boolean;
  2210. var
  2211. i: integer;
  2212. fRo2, fRi2, fDE, fVal, r, nearest: Double;
  2213. polynom: array [0 .. 4] of Double;
  2214. polyRoots: TDoubleArray;
  2215. localStart, localVector: TGLVector;
  2216. vi, vc: TGLVector;
  2217. begin
  2218. // compute coefficients of quartic polynomial
  2219. fRo2 := Sqr(MajorRadius);
  2220. fRi2 := Sqr(MinorRadius);
  2221. localStart := AbsoluteToLocal(rayStart);
  2222. localVector := AbsoluteToLocal(rayVector);
  2223. NormalizeVector(localVector);
  2224. fDE := VectorDotProduct(localStart, localVector);
  2225. fVal := VectorNorm(localStart) - (fRo2 + fRi2);
  2226. polynom[0] := Sqr(fVal) - 4.0 * fRo2 * (fRi2 - Sqr(localStart.Z));
  2227. polynom[1] := 4.0 * fDE * fVal + 8.0 * fRo2 * localVector.Z * localStart.Z;
  2228. polynom[2] := 2.0 * fVal + 4.0 * Sqr(fDE) + 4.0 * fRo2 * Sqr(localVector.Z);
  2229. polynom[3] := 4.0 * fDE;
  2230. polynom[4] := 1;
  2231. // solve the quartic
  2232. polyRoots := SolveQuartic(@polynom[0]);
  2233. // search for closest point
  2234. Result := (Length(polyRoots) > 0);
  2235. if Result then
  2236. begin
  2237. nearest := 1E20;
  2238. for i := 0 to High(polyRoots) do
  2239. begin
  2240. r := polyRoots[i];
  2241. if (r > 0) and (r < nearest) then
  2242. begin
  2243. nearest := r;
  2244. Result := true;
  2245. end;
  2246. end;
  2247. vi := VectorCombine(localStart, localVector, 1, nearest);
  2248. if Assigned(intersectPoint) then
  2249. SetVector(intersectPoint^, LocalToAbsolute(vi));
  2250. if Assigned(intersectNormal) then
  2251. begin
  2252. // project vi on local torus plane
  2253. vc.X := vi.X;
  2254. vc.Y := vi.Y;
  2255. vc.Z := 0;
  2256. // project vc on MajorRadius circle
  2257. ScaleVector(vc, MajorRadius / (VectorLength(vc) + 0.000001));
  2258. // calculate circle to intersect vector (gives normal);
  2259. SubtractVector(vi, vc);
  2260. // return to absolute coordinates and normalize
  2261. vi.W := 0;
  2262. SetVector(intersectNormal^, LocalToAbsolute(vi));
  2263. end;
  2264. end;
  2265. end;
  2266. // ------------------
  2267. // ------------------ TGLArrowLine ------------------
  2268. // ------------------
  2269. constructor TGLArrowLine.Create(AOwner: TComponent);
  2270. begin
  2271. inherited;
  2272. FTopRadius := 0.1;
  2273. BottomRadius := 0.1;
  2274. fTopArrowHeadRadius := 0.2;
  2275. fTopArrowHeadHeight := 0.5;
  2276. fBottomArrowHeadRadius := 0.2;
  2277. fBottomArrowHeadHeight := 0.5;
  2278. FHeadStackingStyle := ahssStacked;
  2279. (* by default there is not much point having the top of the line (cylinder)
  2280. showing as it is coincidental with the Toparrowhead bottom.
  2281. Note I've defaulted to "vector" type arrows (arrow head on top only *)
  2282. FParts := [alLine, alTopArrow];
  2283. end;
  2284. procedure TGLArrowLine.SetTopRadius(const aValue: Single);
  2285. begin
  2286. if aValue <> FTopRadius then
  2287. begin
  2288. FTopRadius := aValue;
  2289. StructureChanged;
  2290. end;
  2291. end;
  2292. procedure TGLArrowLine.SetTopArrowHeadHeight(const aValue: Single);
  2293. begin
  2294. if aValue <> fTopArrowHeadHeight then
  2295. begin
  2296. fTopArrowHeadHeight := aValue;
  2297. StructureChanged;
  2298. end;
  2299. end;
  2300. procedure TGLArrowLine.SetTopArrowHeadRadius(const aValue: Single);
  2301. begin
  2302. if aValue <> fTopArrowHeadRadius then
  2303. begin
  2304. fTopArrowHeadRadius := aValue;
  2305. StructureChanged;
  2306. end;
  2307. end;
  2308. procedure TGLArrowLine.SetBottomArrowHeadHeight(const aValue: Single);
  2309. begin
  2310. if aValue <> fBottomArrowHeadHeight then
  2311. begin
  2312. fBottomArrowHeadHeight := aValue;
  2313. StructureChanged;
  2314. end;
  2315. end;
  2316. procedure TGLArrowLine.SetBottomArrowHeadRadius(const aValue: Single);
  2317. begin
  2318. if aValue <> fBottomArrowHeadRadius then
  2319. begin
  2320. fBottomArrowHeadRadius := aValue;
  2321. StructureChanged;
  2322. end;
  2323. end;
  2324. procedure TGLArrowLine.SetParts(aValue: TGLArrowLineParts);
  2325. begin
  2326. if aValue <> FParts then
  2327. begin
  2328. FParts := aValue;
  2329. StructureChanged;
  2330. end;
  2331. end;
  2332. procedure TGLArrowLine.SetHeadStackingStyle(const val: TGLArrowHeadStyle);
  2333. begin
  2334. if val <> FHeadStackingStyle then
  2335. begin
  2336. FHeadStackingStyle := val;
  2337. StructureChanged;
  2338. end;
  2339. end;
  2340. procedure TGLArrowLine.BuildList(var rci: TGLRenderContextInfo);
  2341. var
  2342. quadric: PGLUquadricObj;
  2343. cylHeight, cylOffset, headInfluence: Single;
  2344. begin
  2345. case HeadStackingStyle of
  2346. ahssCentered:
  2347. headInfluence := 0.5;
  2348. ahssIncluded:
  2349. headInfluence := 1;
  2350. else // ahssStacked
  2351. headInfluence := 0;
  2352. end;
  2353. cylHeight := Height;
  2354. cylOffset := -FHeight * 0.5;
  2355. // create a new quadric
  2356. quadric := gluNewQuadric;
  2357. SetupQuadricParams(quadric);
  2358. // does the top arrow part - the cone
  2359. if alTopArrow in Parts then
  2360. begin
  2361. cylHeight := cylHeight - TopArrowHeadHeight * headInfluence;
  2362. gl.PushMatrix;
  2363. gl.Translatef(0, 0, Height * 0.5 - TopArrowHeadHeight * headInfluence);
  2364. gluCylinder(quadric, fTopArrowHeadRadius, 0, fTopArrowHeadHeight,
  2365. Slices, Stacks);
  2366. // top of a disk is defined as outside
  2367. SetInvertedQuadricOrientation(quadric);
  2368. if alLine in Parts then
  2369. gluDisk(quadric, FTopRadius, fTopArrowHeadRadius, Slices, FLoops)
  2370. else
  2371. gluDisk(quadric, 0, fTopArrowHeadRadius, Slices, FLoops);
  2372. gl.PopMatrix;
  2373. end;
  2374. // does the bottom arrow part - another cone
  2375. if alBottomArrow in Parts then
  2376. begin
  2377. cylHeight := cylHeight - BottomArrowHeadHeight * headInfluence;
  2378. cylOffset := cylOffset + BottomArrowHeadHeight * headInfluence;
  2379. gl.PushMatrix;
  2380. // make the bottom arrow point in the other direction
  2381. gl.Rotatef(180, 1, 0, 0);
  2382. gl.Translatef(0, 0, Height * 0.5 - BottomArrowHeadHeight * headInfluence);
  2383. SetNormalQuadricOrientation(quadric);
  2384. gluCylinder(quadric, fBottomArrowHeadRadius, 0, fBottomArrowHeadHeight,
  2385. Slices, Stacks);
  2386. // top of a disk is defined as outside
  2387. SetInvertedQuadricOrientation(quadric);
  2388. if alLine in Parts then
  2389. gluDisk(quadric, FBottomRadius, fBottomArrowHeadRadius, Slices, FLoops)
  2390. else
  2391. gluDisk(quadric, 0, fBottomArrowHeadRadius, Slices, FLoops);
  2392. gl.PopMatrix;
  2393. end;
  2394. // does the cylinder that makes the line
  2395. if (cylHeight > 0) and (alLine in Parts) then
  2396. begin
  2397. gl.PushMatrix;
  2398. gl.Translatef(0, 0, cylOffset);
  2399. SetNormalQuadricOrientation(quadric);
  2400. gluCylinder(quadric, FBottomRadius, FTopRadius, cylHeight, FSlices,
  2401. FStacks);
  2402. if not(alTopArrow in Parts) then
  2403. begin
  2404. gl.PushMatrix;
  2405. gl.Translatef(0, 0, cylHeight);
  2406. gluDisk(quadric, 0, FTopRadius, FSlices, FLoops);
  2407. gl.PopMatrix;
  2408. end;
  2409. if not(alBottomArrow in Parts) then
  2410. begin
  2411. // swap quadric orientation because top of a disk is defined as outside
  2412. SetInvertedQuadricOrientation(quadric);
  2413. gluDisk(quadric, 0, FBottomRadius, FSlices, FLoops);
  2414. end;
  2415. gl.PopMatrix;
  2416. end;
  2417. gluDeleteQuadric(quadric);
  2418. end;
  2419. procedure TGLArrowLine.Assign(Source: TPersistent);
  2420. begin
  2421. if Assigned(Source) and (Source is TGLArrowLine) then
  2422. begin
  2423. FParts := TGLArrowLine(Source).FParts;
  2424. FTopRadius := TGLArrowLine(Source).FTopRadius;
  2425. fTopArrowHeadHeight := TGLArrowLine(Source).fTopArrowHeadHeight;
  2426. fTopArrowHeadRadius := TGLArrowLine(Source).fTopArrowHeadRadius;
  2427. fBottomArrowHeadHeight := TGLArrowLine(Source).fBottomArrowHeadHeight;
  2428. fBottomArrowHeadRadius := TGLArrowLine(Source).fBottomArrowHeadRadius;
  2429. FHeadStackingStyle := TGLArrowLine(Source).FHeadStackingStyle;
  2430. end;
  2431. inherited Assign(Source);
  2432. end;
  2433. // ------------------
  2434. // ------------------ TGLArrowArc ------------------
  2435. // ------------------
  2436. constructor TGLArrowArc.Create(AOwner: TComponent);
  2437. begin
  2438. inherited;
  2439. FStacks := 16;
  2440. fArcRadius := 0.5;
  2441. FStartAngle := 0;
  2442. FStopAngle := 360;
  2443. FTopRadius := 0.1;
  2444. BottomRadius := 0.1;
  2445. fTopArrowHeadRadius := 0.2;
  2446. fTopArrowHeadHeight := 0.5;
  2447. fBottomArrowHeadRadius := 0.2;
  2448. fBottomArrowHeadHeight := 0.5;
  2449. FHeadStackingStyle := ahssStacked;
  2450. FParts := [aaArc, aaTopArrow];
  2451. end;
  2452. procedure TGLArrowArc.SetArcRadius(const aValue: Single);
  2453. begin
  2454. if fArcRadius <> aValue then
  2455. begin
  2456. fArcRadius := aValue;
  2457. FMesh := nil;
  2458. StructureChanged;
  2459. end;
  2460. end;
  2461. procedure TGLArrowArc.SetStartAngle(const aValue: Single);
  2462. begin
  2463. if FStartAngle <> aValue then
  2464. begin
  2465. FStartAngle := aValue;
  2466. FMesh := nil;
  2467. StructureChanged;
  2468. end;
  2469. end;
  2470. procedure TGLArrowArc.SetStopAngle(const aValue: Single);
  2471. begin
  2472. if FStopAngle <> aValue then
  2473. begin
  2474. FStopAngle := aValue;
  2475. FMesh := nil;
  2476. StructureChanged;
  2477. end;
  2478. end;
  2479. procedure TGLArrowArc.SetTopRadius(const aValue: Single);
  2480. begin
  2481. if aValue <> FTopRadius then
  2482. begin
  2483. FTopRadius := aValue;
  2484. FMesh := nil;
  2485. StructureChanged;
  2486. end;
  2487. end;
  2488. procedure TGLArrowArc.SetTopArrowHeadHeight(const aValue: Single);
  2489. begin
  2490. if aValue <> fTopArrowHeadHeight then
  2491. begin
  2492. fTopArrowHeadHeight := aValue;
  2493. FMesh := nil;
  2494. StructureChanged;
  2495. end;
  2496. end;
  2497. procedure TGLArrowArc.SetTopArrowHeadRadius(const aValue: Single);
  2498. begin
  2499. if aValue <> fTopArrowHeadRadius then
  2500. begin
  2501. fTopArrowHeadRadius := aValue;
  2502. FMesh := nil;
  2503. StructureChanged;
  2504. end;
  2505. end;
  2506. procedure TGLArrowArc.SetBottomArrowHeadHeight(const aValue: Single);
  2507. begin
  2508. if aValue <> fBottomArrowHeadHeight then
  2509. begin
  2510. fBottomArrowHeadHeight := aValue;
  2511. FMesh := nil;
  2512. StructureChanged;
  2513. end;
  2514. end;
  2515. procedure TGLArrowArc.SetBottomArrowHeadRadius(const aValue: Single);
  2516. begin
  2517. if aValue <> fBottomArrowHeadRadius then
  2518. begin
  2519. fBottomArrowHeadRadius := aValue;
  2520. FMesh := nil;
  2521. StructureChanged;
  2522. end;
  2523. end;
  2524. procedure TGLArrowArc.SetParts(aValue: TGLArrowArcParts);
  2525. begin
  2526. if aValue <> FParts then
  2527. begin
  2528. FParts := aValue;
  2529. FMesh := nil;
  2530. StructureChanged;
  2531. end;
  2532. end;
  2533. procedure TGLArrowArc.SetHeadStackingStyle(const val: TGLArrowHeadStyle);
  2534. begin
  2535. if val <> FHeadStackingStyle then
  2536. begin
  2537. FHeadStackingStyle := val;
  2538. FMesh := nil;
  2539. StructureChanged;
  2540. end;
  2541. end;
  2542. procedure TGLArrowArc.BuildList(var rci: TGLRenderContextInfo);
  2543. procedure EmitVertex(ptr: PGLVertexRec; L1, L2: integer);
  2544. begin
  2545. XGL.TexCoord2fv(@ptr^.TexCoord);
  2546. gl.Normal3fv(@ptr^.Normal);
  2547. if L1 > -1 then
  2548. gl.VertexAttrib3fv(L1, @ptr.Tangent);
  2549. if L2 > -1 then
  2550. gl.VertexAttrib3fv(L2, @ptr.Binormal);
  2551. gl.Vertex3fv(@ptr^.Position);
  2552. end;
  2553. var
  2554. i, j: integer;
  2555. Theta, Phi, Theta1, cosPhi, sinPhi, dist: Single;
  2556. cosTheta1, sinTheta1: Single;
  2557. ringDelta, sideDelta: Single;
  2558. ringDir: TAffineVector;
  2559. iFact, jFact: Single;
  2560. pVertex: PGLVertexRec;
  2561. TanLoc, BinLoc: Integer;
  2562. MeshSize: integer;
  2563. MeshIndex: integer;
  2564. ConeCenter: TGLVertexRec;
  2565. StartOffset, StopOffset: Single;
  2566. begin
  2567. if FMesh = nil then
  2568. begin
  2569. MeshIndex := 0;
  2570. MeshSize := 0;
  2571. // Check Parts
  2572. if aaArc in FParts then
  2573. MeshSize := MeshSize + FStacks + 1;
  2574. if aaTopArrow in FParts then
  2575. MeshSize := MeshSize + 3
  2576. else
  2577. MeshSize := MeshSize + 1;
  2578. if aaBottomArrow in FParts then
  2579. MeshSize := MeshSize + 3
  2580. else
  2581. MeshSize := MeshSize + 1;
  2582. // Allocate Mesh
  2583. SetLength(FMesh, MeshSize);
  2584. case FHeadStackingStyle of
  2585. ahssStacked:
  2586. begin
  2587. StartOffset := 0;
  2588. StopOffset := 0;
  2589. end;
  2590. ahssCentered:
  2591. begin
  2592. if aaBottomArrow in Parts then
  2593. StartOffset :=
  2594. RadToDeg(ArcTan(0.5 * fBottomArrowHeadHeight / fArcRadius))
  2595. else
  2596. StartOffset :=0;
  2597. if aaTopArrow in Parts then
  2598. StopOffset :=
  2599. RadToDeg(ArcTan(0.5 * fTopArrowHeadHeight / fArcRadius))
  2600. else
  2601. StopOffset :=0;
  2602. end ;
  2603. ahssIncluded:
  2604. begin
  2605. if aaBottomArrow in Parts then
  2606. StartOffset := RadToDeg(ArcTan(fBottomArrowHeadHeight / fArcRadius))
  2607. else
  2608. StartOffset :=0;
  2609. if aaTopArrow in Parts then
  2610. StopOffset := RadToDeg(ArcTan(fTopArrowHeadHeight / fArcRadius))
  2611. else
  2612. StopOffset :=0;
  2613. end ;
  2614. else
  2615. StartOffset := 0;
  2616. StopOffset := 0;
  2617. end;
  2618. // handle texture generation
  2619. ringDelta := (((FStopAngle - StopOffset) - (FStartAngle + StartOffset)) /
  2620. 360) * c2PI / FStacks;
  2621. sideDelta := c2PI / FSlices;
  2622. iFact := 1 / FStacks;
  2623. jFact := 1 / FSlices;
  2624. if aaArc in FParts then
  2625. begin
  2626. Theta := DegToRadian(FStartAngle + StartOffset) - ringDelta;
  2627. for i := FStacks downto 0 do
  2628. begin
  2629. SetLength(FMesh[i], FSlices + 1);
  2630. Theta1 := Theta + ringDelta;
  2631. SinCosine(Theta1, sinTheta1, cosTheta1);
  2632. Phi := 0;
  2633. for j := FSlices downto 0 do
  2634. begin
  2635. Phi := Phi + sideDelta;
  2636. SinCosine(Phi, sinPhi, cosPhi);
  2637. dist := fArcRadius + Lerp(FTopRadius, FBottomRadius, i * iFact) * cosPhi;
  2638. FMesh[i][j].Position := Vector3fMake(cosTheta1 * dist,
  2639. -sinTheta1 * dist, Lerp(FTopRadius, FBottomRadius, i * iFact) * sinPhi);
  2640. ringDir := FMesh[i][j].Position;
  2641. ringDir.Z := 0.0;
  2642. NormalizeVector(ringDir);
  2643. FMesh[i][j].Normal := Vector3fMake(cosTheta1 * cosPhi,
  2644. -sinTheta1 * cosPhi, sinPhi);
  2645. FMesh[i][j].Tangent := VectorCrossProduct(ZVector, ringDir);
  2646. FMesh[i][j].Binormal := VectorCrossProduct(FMesh[i][j].Normal,
  2647. FMesh[i][j].Tangent);
  2648. FMesh[i][j].TexCoord := Vector2fMake(i * iFact, j * jFact);
  2649. end;
  2650. Theta := Theta1;
  2651. end;
  2652. MeshIndex := FStacks + 1;
  2653. begin
  2654. if GL.ARB_shader_objects and (rci.GLStates.CurrentProgram > 0) then
  2655. begin
  2656. TanLoc := gl.GetAttribLocation(rci.GLStates.CurrentProgram,
  2657. PAnsiChar(TangentAttributeName));
  2658. BinLoc := gl.GetAttribLocation(rci.GLStates.CurrentProgram,
  2659. PAnsiChar(BinormalAttributeName));
  2660. end
  2661. else
  2662. begin
  2663. TanLoc := -1;
  2664. BinLoc := TanLoc;
  2665. end;
  2666. gl.Begin_(GL_TRIANGLES);
  2667. for i := FStacks - 1 downto 0 do
  2668. for j := FSlices - 1 downto 0 do
  2669. begin
  2670. pVertex := @FMesh[i][j];
  2671. EmitVertex(pVertex, TanLoc, BinLoc);
  2672. pVertex := @FMesh[i][j + 1];
  2673. EmitVertex(pVertex, TanLoc, BinLoc);
  2674. pVertex := @FMesh[i + 1][j];
  2675. EmitVertex(pVertex, TanLoc, BinLoc);
  2676. pVertex := @FMesh[i + 1][j + 1];
  2677. EmitVertex(pVertex, TanLoc, BinLoc);
  2678. pVertex := @FMesh[i + 1][j];
  2679. EmitVertex(pVertex, TanLoc, BinLoc);
  2680. pVertex := @FMesh[i][j + 1];
  2681. EmitVertex(pVertex, TanLoc, BinLoc);
  2682. end;
  2683. gl.End_;
  2684. end;
  2685. end;
  2686. // Build Arrow or start cap
  2687. if aaBottomArrow in FParts then
  2688. begin
  2689. SetLength(FMesh[MeshIndex], FSlices + 1);
  2690. SetLength(FMesh[MeshIndex + 1], FSlices + 1);
  2691. SetLength(FMesh[MeshIndex + 2], FSlices + 1);
  2692. Theta1 := DegToRadian(FStartAngle + StartOffset);
  2693. SinCosine(Theta1, sinTheta1, cosTheta1);
  2694. ConeCenter.Position := Vector3fMake(cosTheta1 * fArcRadius,
  2695. -sinTheta1 * fArcRadius, 0);
  2696. Phi := 0;
  2697. for j := FSlices downto 0 do
  2698. begin
  2699. Phi := Phi + sideDelta;
  2700. SinCosine(Phi, sinPhi, cosPhi);
  2701. dist := fArcRadius + fBottomArrowHeadRadius * cosPhi;
  2702. // Cap
  2703. FMesh[MeshIndex][J].Position := Vector3fMake(cosTheta1 * dist,
  2704. -sinTheta1 * dist, fBottomArrowHeadRadius * sinPhi);
  2705. ringDir := FMesh[MeshIndex][j].Position;
  2706. ringDir.Z := 0.0;
  2707. NormalizeVector(ringDir);
  2708. FMesh[MeshIndex][j].Normal := VectorCrossProduct(ringDir, ZVector);
  2709. FMesh[MeshIndex][j].Tangent := ringDir;
  2710. FMesh[MeshIndex][j].Binormal := ZVector;
  2711. FMesh[MeshIndex][j].TexCoord := Vector2fMake(1, j * jFact);
  2712. // Cone
  2713. FMesh[MeshIndex+1][j].Position := Vector3fMake(cosTheta1 * dist,
  2714. -sinTheta1 * dist, fBottomArrowHeadRadius * sinPhi);
  2715. FMesh[MeshIndex+2][j].Position := VectorAdd(ConeCenter.Position,
  2716. Vector3fMake(sinTheta1 * fBottomArrowHeadHeight,
  2717. cosTheta1 * fBottomArrowHeadHeight, 0));
  2718. FMesh[MeshIndex + 1][j].Tangent :=
  2719. VectorNormalize(VectorSubtract(FMesh[MeshIndex + 1][j].Position,
  2720. FMesh[MeshIndex + 2][j].Position));
  2721. FMesh[MeshIndex + 2][j].Tangent := FMesh[MeshIndex + 1][j].Tangent;
  2722. FMesh[MeshIndex + 1][j].Binormal := Vector3fMake(cosTheta1 * -sinPhi,
  2723. sinTheta1 * sinPhi, cosPhi);
  2724. FMesh[MeshIndex + 2][j].Binormal := FMesh[MeshIndex + 1][j].Binormal;
  2725. FMesh[MeshIndex + 1][j].Normal :=
  2726. VectorCrossProduct(FMesh[MeshIndex + 1][j].Binormal,
  2727. FMesh[MeshIndex + 1][j].Tangent);
  2728. FMesh[MeshIndex + 2][j].Normal := FMesh[MeshIndex + 1][j].Normal;
  2729. FMesh[MeshIndex + 1][j].TexCoord := Vector2fMake(0, j * jFact);
  2730. FMesh[MeshIndex + 2][j].TexCoord := Vector2fMake(1, j * jFact);
  2731. end;
  2732. ConeCenter.Normal := FMesh[MeshIndex][0].Normal;
  2733. ConeCenter.Tangent := FMesh[MeshIndex][0].Tangent;
  2734. ConeCenter.Binormal := FMesh[MeshIndex][0].Binormal;
  2735. ConeCenter.TexCoord := Vector2fMake(0, 0);
  2736. begin
  2737. if GL.ARB_shader_objects and (rci.GLStates.CurrentProgram > 0) then
  2738. begin
  2739. TanLoc := gl.GetAttribLocation(rci.GLStates.CurrentProgram,
  2740. PAnsiChar(TangentAttributeName));
  2741. BinLoc := gl.GetAttribLocation(rci.GLStates.CurrentProgram,
  2742. PAnsiChar(BinormalAttributeName));
  2743. end
  2744. else
  2745. begin
  2746. TanLoc := -1;
  2747. BinLoc := TanLoc;
  2748. end;
  2749. gl.Begin_(GL_TRIANGLE_FAN);
  2750. pVertex := @ConeCenter;
  2751. EmitVertex(pVertex, TanLoc, BinLoc);
  2752. for j := FSlices downto 0 do
  2753. begin
  2754. pVertex := @FMesh[MeshIndex][j];
  2755. EmitVertex(pVertex, TanLoc, BinLoc);
  2756. end;
  2757. gl.End_;
  2758. gl.Begin_(GL_TRIANGLES);
  2759. for j := FSlices - 1 downto 0 do
  2760. begin
  2761. pVertex := @FMesh[MeshIndex + 1][j];
  2762. EmitVertex(pVertex, TanLoc, BinLoc);
  2763. pVertex := @FMesh[MeshIndex + 1][j + 1];
  2764. EmitVertex(pVertex, TanLoc, BinLoc);
  2765. pVertex := @FMesh[MeshIndex + 2][j];
  2766. EmitVertex(pVertex, TanLoc, BinLoc);
  2767. pVertex := @FMesh[MeshIndex + 2][j + 1];
  2768. EmitVertex(pVertex, TanLoc, BinLoc);
  2769. pVertex := @FMesh[MeshIndex + 2][j];
  2770. EmitVertex(pVertex, TanLoc, BinLoc);
  2771. pVertex := @FMesh[MeshIndex + 1][j + 1];
  2772. EmitVertex(pVertex, TanLoc, BinLoc);
  2773. end;
  2774. gl.End_;
  2775. end;
  2776. MeshIndex := MeshIndex + 3;
  2777. end
  2778. else
  2779. begin
  2780. SetLength(FMesh[MeshIndex], FSlices + 1);
  2781. Theta1 := DegToRadian(FStartAngle);
  2782. SinCosine(Theta1, sinTheta1, cosTheta1);
  2783. Phi := 0;
  2784. for j := FSlices downto 0 do
  2785. begin
  2786. Phi := Phi + sideDelta;
  2787. SinCosine(Phi, sinPhi, cosPhi);
  2788. dist := fArcRadius + fBottomRadius * cosPhi;
  2789. FMesh[MeshIndex][j].Position := Vector3fMake(cosTheta1 * dist,
  2790. -sinTheta1 * dist, FBottomRadius * sinPhi);
  2791. ringDir := FMesh[MeshIndex][j].Position;
  2792. ringDir.Z := 0.0;
  2793. NormalizeVector(ringDir);
  2794. FMesh[MeshIndex][j].Normal := VectorCrossProduct(ZVector, ringDir);
  2795. FMesh[MeshIndex][j].Tangent := ringDir;
  2796. FMesh[MeshIndex][j].Binormal := ZVector;
  2797. FMesh[MeshIndex][j].TexCoord := Vector2fMake(0, j * jFact);
  2798. end;
  2799. ConeCenter.Position := Vector3fMake(cosTheta1 * fArcRadius,
  2800. -sinTheta1 * fArcRadius, 0);
  2801. ConeCenter.Normal := FMesh[MeshIndex][0].Normal;
  2802. ConeCenter.Tangent := FMesh[MeshIndex][0].Tangent;
  2803. ConeCenter.Binormal := FMesh[MeshIndex][0].Binormal;
  2804. ConeCenter.TexCoord := Vector2fMake(1, 1);
  2805. begin
  2806. if GL.ARB_shader_objects and (rci.GLStates.CurrentProgram > 0) then
  2807. begin
  2808. TanLoc := gl.GetAttribLocation(rci.GLStates.CurrentProgram,
  2809. PAnsiChar(TangentAttributeName));
  2810. BinLoc := gl.GetAttribLocation(rci.GLStates.CurrentProgram,
  2811. PAnsiChar(BinormalAttributeName));
  2812. end
  2813. else
  2814. begin
  2815. TanLoc := -1;
  2816. BinLoc := TanLoc;
  2817. end;
  2818. gl.Begin_(GL_TRIANGLE_FAN);
  2819. pVertex := @ConeCenter;
  2820. EmitVertex(pVertex, TanLoc, BinLoc);
  2821. for j := 0 to FSlices do
  2822. begin
  2823. pVertex := @FMesh[MeshIndex][j];
  2824. EmitVertex(pVertex, TanLoc, BinLoc);
  2825. end;
  2826. gl.End_;
  2827. end;
  2828. MeshIndex := MeshIndex + 1;
  2829. end;
  2830. if aaTopArrow in FParts then
  2831. begin
  2832. SetLength(FMesh[MeshIndex], FSlices + 1);
  2833. SetLength(FMesh[MeshIndex + 1], FSlices + 1);
  2834. SetLength(FMesh[MeshIndex + 2], FSlices + 1);
  2835. Theta1 := DegToRadian(FStopAngle - StopOffset);
  2836. SinCosine(Theta1, sinTheta1, cosTheta1);
  2837. ConeCenter.Position := Vector3fMake(cosTheta1 * fArcRadius,
  2838. -sinTheta1 * fArcRadius, 0);
  2839. Phi := 0;
  2840. for j := FSlices downto 0 do
  2841. begin
  2842. Phi := Phi + sideDelta;
  2843. SinCosine(Phi, sinPhi, cosPhi);
  2844. dist := fArcRadius + fTopArrowHeadRadius * cosPhi;
  2845. // Cap
  2846. FMesh[MeshIndex][j].Position := Vector3fMake(cosTheta1 * dist,
  2847. -sinTheta1 * dist, fTopArrowHeadRadius * sinPhi);
  2848. ringDir := FMesh[MeshIndex][j].Position;
  2849. ringDir.Z := 0.0;
  2850. NormalizeVector(ringDir);
  2851. FMesh[MeshIndex][j].Normal := VectorCrossProduct(ZVector, ringDir);
  2852. FMesh[MeshIndex][j].Tangent := ringDir;
  2853. FMesh[MeshIndex][j].Binormal := ZVector;
  2854. FMesh[MeshIndex][j].TexCoord := Vector2fMake(0, j * jFact);
  2855. // Cone
  2856. FMesh[MeshIndex + 1][j].Position := Vector3fMake(cosTheta1 * dist,
  2857. -sinTheta1 * dist, fTopArrowHeadRadius * sinPhi);
  2858. FMesh[MeshIndex + 2][j].Position := VectorSubtract(ConeCenter.Position,
  2859. Vector3fMake(sinTheta1 * fTopArrowHeadHeight,
  2860. cosTheta1 * fTopArrowHeadHeight, 0));
  2861. FMesh[MeshIndex + 1][j].Tangent :=
  2862. VectorNormalize(VectorSubtract(FMesh[MeshIndex + 2][j].Position,
  2863. FMesh[MeshIndex + 1][j].Position));
  2864. FMesh[MeshIndex + 2][j].Tangent := FMesh[MeshIndex + 1][j].Tangent;
  2865. FMesh[MeshIndex + 1][j].Binormal := Vector3fMake(cosTheta1 * -sinPhi,
  2866. sinTheta1 * sinPhi, cosPhi);
  2867. FMesh[MeshIndex + 2][j].Binormal := FMesh[MeshIndex + 1][j].Binormal;
  2868. FMesh[MeshIndex + 1][j].Normal :=
  2869. VectorCrossProduct(FMesh[MeshIndex + 1][j].Binormal,
  2870. FMesh[MeshIndex + 1][j].Tangent);
  2871. FMesh[MeshIndex + 2][j].Normal := FMesh[MeshIndex + 1][j].Normal;
  2872. FMesh[MeshIndex + 1][j].TexCoord := Vector2fMake(1, j * jFact);
  2873. FMesh[MeshIndex + 2][j].TexCoord := Vector2fMake(0, j * jFact);
  2874. end;
  2875. ConeCenter.Normal := FMesh[MeshIndex][0].Normal;
  2876. ConeCenter.Tangent := FMesh[MeshIndex][0].Tangent;
  2877. ConeCenter.Binormal := FMesh[MeshIndex][0].Binormal;
  2878. ConeCenter.TexCoord := Vector2fMake(1, 1);
  2879. begin
  2880. if GL.ARB_shader_objects and (rci.GLStates.CurrentProgram > 0) then
  2881. begin
  2882. TanLoc := gl.GetAttribLocation(rci.GLStates.CurrentProgram,
  2883. PAnsiChar(TangentAttributeName));
  2884. BinLoc := gl.GetAttribLocation(rci.GLStates.CurrentProgram,
  2885. PAnsiChar(BinormalAttributeName));
  2886. end
  2887. else
  2888. begin
  2889. TanLoc := -1;
  2890. BinLoc := TanLoc;
  2891. end;
  2892. gl.Begin_(GL_TRIANGLE_FAN);
  2893. pVertex := @ConeCenter;
  2894. EmitVertex(pVertex, TanLoc, BinLoc);
  2895. for j := 0 to FSlices do
  2896. begin
  2897. pVertex := @FMesh[MeshIndex][j];
  2898. EmitVertex(pVertex, TanLoc, BinLoc);
  2899. end;
  2900. gl.End_;
  2901. gl.Begin_(GL_TRIANGLES);
  2902. for j := FSlices - 1 downto 0 do
  2903. begin
  2904. pVertex := @FMesh[MeshIndex + 2][j];
  2905. EmitVertex(pVertex, TanLoc, BinLoc);
  2906. pVertex := @FMesh[MeshIndex + 2][j + 1];
  2907. EmitVertex(pVertex, TanLoc, BinLoc);
  2908. pVertex := @FMesh[MeshIndex + 1][j];
  2909. EmitVertex(pVertex, TanLoc, BinLoc);
  2910. pVertex := @FMesh[MeshIndex + 1][j + 1];
  2911. EmitVertex(pVertex, TanLoc, BinLoc);
  2912. pVertex := @FMesh[MeshIndex + 1][j];
  2913. EmitVertex(pVertex, TanLoc, BinLoc);
  2914. pVertex := @FMesh[MeshIndex + 2][j + 1];
  2915. EmitVertex(pVertex, TanLoc, BinLoc);
  2916. end;
  2917. gl.End_;
  2918. end;
  2919. end
  2920. else
  2921. begin
  2922. SetLength(FMesh[MeshIndex], FSlices + 1);
  2923. Theta1 := DegToRadian(FStopAngle);
  2924. SinCosine(Theta1, sinTheta1, cosTheta1);
  2925. Phi := 0;
  2926. for j := FSlices downto 0 do
  2927. begin
  2928. Phi := Phi + sideDelta;
  2929. SinCosine(Phi, sinPhi, cosPhi);
  2930. dist := fArcRadius + fTopRadius * cosPhi;
  2931. FMesh[MeshIndex][j].Position := Vector3fMake(cosTheta1 * dist,
  2932. -sinTheta1 * dist, fTopRadius * sinPhi);
  2933. ringDir := FMesh[MeshIndex][j].Position;
  2934. ringDir.Z := 0.0;
  2935. NormalizeVector(ringDir);
  2936. FMesh[MeshIndex][j].Normal := VectorCrossProduct(ringDir, ZVector);
  2937. FMesh[MeshIndex][j].Tangent := ringDir;
  2938. FMesh[MeshIndex][j].Binormal := VectorNegate(ZVector);
  2939. FMesh[MeshIndex][j].TexCoord := Vector2fMake(1, j * jFact);
  2940. end;
  2941. ConeCenter.Position := Vector3fMake(cosTheta1 * fArcRadius,
  2942. -sinTheta1 * fArcRadius, 0);
  2943. ConeCenter.Normal := FMesh[MeshIndex][0].Normal;
  2944. ConeCenter.Tangent := FMesh[MeshIndex][0].Tangent;
  2945. ConeCenter.Binormal := FMesh[MeshIndex][0].Binormal;
  2946. ConeCenter.TexCoord := Vector2fMake(0, 0);
  2947. begin
  2948. if GL.ARB_shader_objects and (rci.GLStates.CurrentProgram > 0) then
  2949. begin
  2950. TanLoc := gl.GetAttribLocation(rci.GLStates.CurrentProgram,
  2951. PAnsiChar(TangentAttributeName));
  2952. BinLoc := gl.GetAttribLocation(rci.GLStates.CurrentProgram,
  2953. PAnsiChar(BinormalAttributeName));
  2954. end
  2955. else
  2956. begin
  2957. TanLoc := -1;
  2958. BinLoc := TanLoc;
  2959. end;
  2960. gl.Begin_(GL_TRIANGLE_FAN);
  2961. pVertex := @ConeCenter;
  2962. EmitVertex(pVertex, TanLoc, BinLoc);
  2963. for j := FSlices downto 0 do
  2964. begin
  2965. pVertex := @FMesh[MeshIndex][j];
  2966. EmitVertex(pVertex, TanLoc, BinLoc);
  2967. end;
  2968. gl.End_;
  2969. end;
  2970. end;
  2971. end;
  2972. end;
  2973. procedure TGLArrowArc.Assign(Source: TPersistent);
  2974. begin
  2975. if Assigned(Source) and (Source is TGLArrowLine) then
  2976. begin
  2977. FStartAngle := TGLArrowArc(Source).FStartAngle;
  2978. FStopAngle := TGLArrowArc(Source).FStopAngle;
  2979. fArcRadius := TGLArrowArc(Source).fArcRadius;
  2980. FParts := TGLArrowArc(Source).FParts;
  2981. FTopRadius := TGLArrowArc(Source).FTopRadius;
  2982. fTopArrowHeadHeight := TGLArrowArc(Source).fTopArrowHeadHeight;
  2983. fTopArrowHeadRadius := TGLArrowArc(Source).fTopArrowHeadRadius;
  2984. fBottomArrowHeadHeight := TGLArrowArc(Source).fBottomArrowHeadHeight;
  2985. fBottomArrowHeadRadius := TGLArrowArc(Source).fBottomArrowHeadRadius;
  2986. FHeadStackingStyle := TGLArrowArc(Source).FHeadStackingStyle;
  2987. end;
  2988. inherited Assign(Source);
  2989. end;
  2990. // ------------------
  2991. // ------------------ TGLFrustrum ------------------
  2992. // ------------------
  2993. constructor TGLFrustrum.Create(AOwner: TComponent);
  2994. begin
  2995. inherited Create(AOwner);
  2996. FApexHeight := 1;
  2997. FBaseWidth := 1;
  2998. FBaseDepth := 1;
  2999. FHeight := 0.5;
  3000. FParts := cAllFrustrumParts;
  3001. FNormalDirection := ndOutside;
  3002. end;
  3003. procedure TGLFrustrum.BuildList(var rci: TGLRenderContextInfo);
  3004. var
  3005. HBW, HBD: Single; // half of width, half of depth at base
  3006. HTW, HTD: Single; // half of width, half of depth at top of frustrum
  3007. HFH: Single; // half of height, for align to center
  3008. Sign: Single; // +1 or -1
  3009. angle: Single; // in radians
  3010. ASin, ACos: Single;
  3011. begin
  3012. if FNormalDirection = ndInside then
  3013. Sign := -1
  3014. else
  3015. Sign := 1;
  3016. HBW := FBaseWidth * 0.5;
  3017. HBD := FBaseDepth * 0.5;
  3018. HTW := HBW * (FApexHeight - FHeight) / FApexHeight;
  3019. HTD := HBD * (FApexHeight - FHeight) / FApexHeight;
  3020. HFH := FHeight * 0.5;
  3021. gl.Begin_(GL_QUADS);
  3022. if [fpFront, fpBack] * FParts <> [] then
  3023. begin
  3024. angle := ArcTan(FApexHeight / HBD);
  3025. // angle of front plane with bottom plane
  3026. SinCosine(angle, ASin, ACos);
  3027. if fpFront in FParts then
  3028. begin
  3029. gl.Normal3f(0, Sign * ACos, Sign * ASin);
  3030. XGL.TexCoord2fv(@XYTexPoint);
  3031. gl.Vertex3f(HTW, HFH, HTD);
  3032. XGL.TexCoord2fv(@YTexPoint);
  3033. gl.Vertex3f(-HTW, HFH, HTD);
  3034. XGL.TexCoord2fv(@NullTexPoint);
  3035. gl.Vertex3f(-HBW, -HFH, HBD);
  3036. XGL.TexCoord2fv(@XTexPoint);
  3037. gl.Vertex3f(HBW, -HFH, HBD);
  3038. end;
  3039. if fpBack in FParts then
  3040. begin
  3041. gl.Normal3f(0, Sign * ACos, -Sign * ASin);
  3042. XGL.TexCoord2fv(@YTexPoint);
  3043. gl.Vertex3f(HTW, HFH, -HTD);
  3044. XGL.TexCoord2fv(@NullTexPoint);
  3045. gl.Vertex3f(HBW, -HFH, -HBD);
  3046. XGL.TexCoord2fv(@XTexPoint);
  3047. gl.Vertex3f(-HBW, -HFH, -HBD);
  3048. XGL.TexCoord2fv(@XYTexPoint);
  3049. gl.Vertex3f(-HTW, HFH, -HTD);
  3050. end;
  3051. end;
  3052. if [fpLeft, fpRight] * FParts <> [] then
  3053. begin
  3054. angle := ArcTan(FApexHeight / HBW); // angle of side plane with bottom plane
  3055. SinCosine(angle, ASin, ACos);
  3056. if fpLeft in FParts then
  3057. begin
  3058. gl.Normal3f(-Sign * ASin, Sign * ACos, 0);
  3059. XGL.TexCoord2fv(@XYTexPoint);
  3060. gl.Vertex3f(-HTW, HFH, HTD);
  3061. XGL.TexCoord2fv(@YTexPoint);
  3062. gl.Vertex3f(-HTW, HFH, -HTD);
  3063. XGL.TexCoord2fv(@NullTexPoint);
  3064. gl.Vertex3f(-HBW, -HFH, -HBD);
  3065. XGL.TexCoord2fv(@XTexPoint);
  3066. gl.Vertex3f(-HBW, -HFH, HBD);
  3067. end;
  3068. if fpRight in FParts then
  3069. begin
  3070. gl.Normal3f(Sign * ASin, Sign * ACos, 0);
  3071. XGL.TexCoord2fv(@YTexPoint);
  3072. gl.Vertex3f(HTW, HFH, HTD);
  3073. XGL.TexCoord2fv(@NullTexPoint);
  3074. gl.Vertex3f(HBW, -HFH, HBD);
  3075. XGL.TexCoord2fv(@XTexPoint);
  3076. gl.Vertex3f(HBW, -HFH, -HBD);
  3077. XGL.TexCoord2fv(@XYTexPoint);
  3078. gl.Vertex3f(HTW, HFH, -HTD);
  3079. end;
  3080. end;
  3081. if (fpTop in FParts) and (FHeight < FApexHeight) then
  3082. begin
  3083. gl.Normal3f(0, Sign, 0);
  3084. XGL.TexCoord2fv(@YTexPoint);
  3085. gl.Vertex3f(-HTW, HFH, -HTD);
  3086. XGL.TexCoord2fv(@NullTexPoint);
  3087. gl.Vertex3f(-HTW, HFH, HTD);
  3088. XGL.TexCoord2fv(@XTexPoint);
  3089. gl.Vertex3f(HTW, HFH, HTD);
  3090. XGL.TexCoord2fv(@XYTexPoint);
  3091. gl.Vertex3f(HTW, HFH, -HTD);
  3092. end;
  3093. if fpBottom in FParts then
  3094. begin
  3095. gl.Normal3f(0, -Sign, 0);
  3096. XGL.TexCoord2fv(@NullTexPoint);
  3097. gl.Vertex3f(-HBW, -HFH, -HBD);
  3098. XGL.TexCoord2fv(@XTexPoint);
  3099. gl.Vertex3f(HBW, -HFH, -HBD);
  3100. XGL.TexCoord2fv(@XYTexPoint);
  3101. gl.Vertex3f(HBW, -HFH, HBD);
  3102. XGL.TexCoord2fv(@YTexPoint);
  3103. gl.Vertex3f(-HBW, -HFH, HBD);
  3104. end;
  3105. gl.End_;
  3106. end;
  3107. procedure TGLFrustrum.SetApexHeight(const aValue: Single);
  3108. begin
  3109. if (aValue <> FApexHeight) and (aValue >= 0) then
  3110. begin
  3111. FApexHeight := aValue;
  3112. if FHeight > aValue then
  3113. FHeight := aValue;
  3114. StructureChanged;
  3115. end;
  3116. end;
  3117. procedure TGLFrustrum.SetBaseDepth(const aValue: Single);
  3118. begin
  3119. if (aValue <> FBaseDepth) and (aValue >= 0) then
  3120. begin
  3121. FBaseDepth := aValue;
  3122. StructureChanged;
  3123. end;
  3124. end;
  3125. procedure TGLFrustrum.SetBaseWidth(const aValue: Single);
  3126. begin
  3127. if (aValue <> FBaseWidth) and (aValue >= 0) then
  3128. begin
  3129. FBaseWidth := aValue;
  3130. StructureChanged;
  3131. end;
  3132. end;
  3133. procedure TGLFrustrum.SetHeight(const aValue: Single);
  3134. begin
  3135. if (aValue <> FHeight) and (aValue >= 0) then
  3136. begin
  3137. FHeight := aValue;
  3138. if FApexHeight < aValue then
  3139. FApexHeight := aValue;
  3140. StructureChanged;
  3141. end;
  3142. end;
  3143. procedure TGLFrustrum.SetParts(aValue: TGLFrustrumParts);
  3144. begin
  3145. if aValue <> FParts then
  3146. begin
  3147. FParts := aValue;
  3148. StructureChanged;
  3149. end;
  3150. end;
  3151. procedure TGLFrustrum.SetNormalDirection(aValue: TGLNormalDirection);
  3152. begin
  3153. if aValue <> FNormalDirection then
  3154. begin
  3155. FNormalDirection := aValue;
  3156. StructureChanged;
  3157. end;
  3158. end;
  3159. procedure TGLFrustrum.Assign(Source: TPersistent);
  3160. begin
  3161. if Assigned(Source) and (Source is TGLFrustrum) then
  3162. begin
  3163. FApexHeight := TGLFrustrum(Source).FApexHeight;
  3164. FBaseDepth := TGLFrustrum(Source).FBaseDepth;
  3165. FBaseWidth := TGLFrustrum(Source).FBaseWidth;
  3166. FHeight := TGLFrustrum(Source).FHeight;
  3167. FParts := TGLFrustrum(Source).FParts;
  3168. FNormalDirection := TGLFrustrum(Source).FNormalDirection;
  3169. end;
  3170. inherited Assign(Source);
  3171. end;
  3172. function TGLFrustrum.TopDepth: Single;
  3173. begin
  3174. Result := FBaseDepth * (FApexHeight - FHeight) / FApexHeight;
  3175. end;
  3176. function TGLFrustrum.TopWidth: Single;
  3177. begin
  3178. Result := FBaseWidth * (FApexHeight - FHeight) / FApexHeight;
  3179. end;
  3180. procedure TGLFrustrum.DefineProperties(Filer: TFiler);
  3181. begin
  3182. inherited;
  3183. Filer.DefineBinaryProperty('FrustrumSize', ReadData, WriteData,
  3184. (FApexHeight <> 1) or (FBaseDepth <> 1) or (FBaseWidth <> 1) or
  3185. (FHeight <> 0.5));
  3186. end;
  3187. procedure TGLFrustrum.ReadData(Stream: TStream);
  3188. begin
  3189. with Stream do
  3190. begin
  3191. Read(FApexHeight, SizeOf(FApexHeight));
  3192. Read(FBaseDepth, SizeOf(FBaseDepth));
  3193. Read(FBaseWidth, SizeOf(FBaseWidth));
  3194. Read(FHeight, SizeOf(FHeight));
  3195. end;
  3196. end;
  3197. procedure TGLFrustrum.WriteData(Stream: TStream);
  3198. begin
  3199. with Stream do
  3200. begin
  3201. Write(FApexHeight, SizeOf(FApexHeight));
  3202. Write(FBaseDepth, SizeOf(FBaseDepth));
  3203. Write(FBaseWidth, SizeOf(FBaseWidth));
  3204. Write(FHeight, SizeOf(FHeight));
  3205. end;
  3206. end;
  3207. function TGLFrustrum.AxisAlignedBoundingBoxUnscaled: TAABB;
  3208. var
  3209. aabb: TAABB;
  3210. child: TGLBaseSceneObject;
  3211. i: integer;
  3212. begin
  3213. SetAABB(Result, AxisAlignedDimensionsUnscaled);
  3214. OffsetAABB(Result, VectorMake(0, FHeight * 0.5, 0));
  3215. // not tested for child objects
  3216. for i := 0 to Count - 1 do
  3217. begin
  3218. child := TGLBaseSceneObject(Children[i]);
  3219. aabb := child.AxisAlignedBoundingBoxUnscaled;
  3220. AABBTransform(aabb, child.Matrix^);
  3221. AddAABB(Result, aabb);
  3222. end;
  3223. end;
  3224. function TGLFrustrum.AxisAlignedDimensionsUnscaled: TGLVector;
  3225. begin
  3226. Result.X := FBaseWidth * 0.5;
  3227. Result.Y := FHeight * 0.5;
  3228. Result.Z := FBaseDepth * 0.5;
  3229. Result.W := 0;
  3230. end;
  3231. // ------------------
  3232. // ------------------ TGLPolygon ------------------
  3233. // ------------------
  3234. constructor TGLPolygon.Create(AOwner: TComponent);
  3235. begin
  3236. inherited Create(AOwner);
  3237. FParts := [ppTop, ppBottom];
  3238. end;
  3239. destructor TGLPolygon.Destroy;
  3240. begin
  3241. inherited Destroy;
  3242. end;
  3243. procedure TGLPolygon.SetParts(const val: TGLPolygonParts);
  3244. begin
  3245. if FParts <> val then
  3246. begin
  3247. FParts := val;
  3248. StructureChanged;
  3249. end;
  3250. end;
  3251. procedure TGLPolygon.Assign(Source: TPersistent);
  3252. begin
  3253. if Source is TGLPolygon then
  3254. begin
  3255. FParts := TGLPolygon(Source).FParts;
  3256. end;
  3257. inherited Assign(Source);
  3258. end;
  3259. procedure TGLPolygon.BuildList(var rci: TGLRenderContextInfo);
  3260. var
  3261. Normal: TAffineVector;
  3262. pNorm: PAffineVector;
  3263. begin
  3264. if (Nodes.Count > 1) then
  3265. begin
  3266. Normal := Nodes.Normal;
  3267. if VectorIsNull(Normal) then
  3268. pNorm := nil
  3269. else
  3270. pNorm := @Normal;
  3271. if ppTop in FParts then
  3272. begin
  3273. if SplineMode = lsmLines then
  3274. Nodes.RenderTesselatedPolygon(true, pNorm, 1)
  3275. else
  3276. Nodes.RenderTesselatedPolygon(true, pNorm, Division);
  3277. end;
  3278. // tessellate bottom polygon
  3279. if ppBottom in FParts then
  3280. begin
  3281. if Assigned(pNorm) then
  3282. NegateVector(Normal);
  3283. if SplineMode = lsmLines then
  3284. Nodes.RenderTesselatedPolygon(true, pNorm, 1, true)
  3285. else
  3286. Nodes.RenderTesselatedPolygon(true, pNorm, Division, true);
  3287. end;
  3288. end;
  3289. end;
  3290. //-------------------------------------------------------------
  3291. // ------------------
  3292. // ------------------ TGLTeapot ------------------
  3293. // ------------------
  3294. constructor TGLTeapot.Create(AOwner: TComponent);
  3295. begin
  3296. inherited Create(AOwner);
  3297. FGrid := 5;
  3298. end;
  3299. function TGLTeapot.AxisAlignedDimensionsUnscaled: TGLVector;
  3300. begin
  3301. SetVector(Result, 0.55, 0.25, 0.35);
  3302. end;
  3303. procedure TGLTeapot.BuildList(var rci: TGLRenderContextInfo);
  3304. const
  3305. PatchData: array[0..9, 0..15] of Integer =
  3306. ((102, 103, 104, 105, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15), // rim
  3307. (12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27), // body
  3308. (24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40), // body
  3309. (96, 96, 96, 96, 97, 98, 99, 100, 101, 101, 101, 101, 0, 1, 2, 3), // lid
  3310. (0, 1, 2, 3, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117), // lid
  3311. (118, 118, 118, 118, 124, 122, 119, 121, 123, 126, 125, 120, 40, 39, 38, 37), // bottom
  3312. (41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56), // handle
  3313. (53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 28, 65, 66, 67), // handle
  3314. (68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83), // spout
  3315. (80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95)); // spout
  3316. CPData: array[0..126, 0..2] of Single =
  3317. ((0.2, 0, 2.7), (0.2, -0.112, 2.7), (0.112, -0.2, 2.7), (0, -0.2, 2.7), (1.3375, 0, 2.53125),
  3318. (1.3375, -0.749, 2.53125), (0.749, -1.3375, 2.53125), (0, -1.3375, 2.53125),
  3319. (1.4375, 0, 2.53125), (1.4375, -0.805, 2.53125), (0.805, -1.4375, 2.53125),
  3320. (0, -1.4375, 2.53125), (1.5, 0, 2.4), (1.5, -0.84, 2.4), (0.84, -1.5, 2.4), (0, -1.5, 2.4),
  3321. (1.75, 0, 1.875), (1.75, -0.98, 1.875), (0.98, -1.75, 1.875), (0, -1.75, 1.875), (2, 0, 1.35),
  3322. (2, -1.12, 1.35), (1.12, -2, 1.35), (0, -2, 1.35), (2, 0, 0.9), (2, -1.12, 0.9), (1.12, -2, 0.9),
  3323. (0, -2, 0.9), (-2, 0, 0.9), (2, 0, 0.45), (2, -1.12, 0.45), (1.12, -2, 0.45), (0, -2, 0.45),
  3324. (1.5, 0, 0.225), (1.5, -0.84, 0.225), (0.84, -1.5, 0.225), (0, -1.5, 0.225), (1.5, 0, 0.15),
  3325. (1.5, -0.84, 0.15), (0.84, -1.5, 0.15), (0, -1.5, 0.15), (-1.6, 0, 2.025), (-1.6, -0.3, 2.025),
  3326. (-1.5, -0.3, 2.25), (-1.5, 0, 2.25), (-2.3, 0, 2.025), (-2.3, -0.3, 2.025), (-2.5, -0.3, 2.25),
  3327. (-2.5, 0, 2.25), (-2.7, 0, 2.025), (-2.7, -0.3, 2.025), (-3, -0.3, 2.25), (-3, 0, 2.25),
  3328. (-2.7, 0, 1.8), (-2.7, -0.3, 1.8), (-3, -0.3, 1.8), (-3, 0, 1.8), (-2.7, 0, 1.575),
  3329. (-2.7, -0.3, 1.575), (-3, -0.3, 1.35), (-3, 0, 1.35), (-2.5, 0, 1.125), (-2.5, -0.3, 1.125),
  3330. (-2.65, -0.3, 0.9375), (-2.65, 0, 0.9375), (-2, -0.3, 0.9), (-1.9, -0.3, 0.6), (-1.9, 0, 0.6),
  3331. (1.7, 0, 1.425), (1.7, -0.66, 1.425), (1.7, -0.66, 0.6), (1.7, 0, 0.6), (2.6, 0, 1.425),
  3332. (2.6, -0.66, 1.425), (3.1, -0.66, 0.825), (3.1, 0, 0.825), (2.3, 0, 2.1), (2.3, -0.25, 2.1),
  3333. (2.4, -0.25, 2.025), (2.4, 0, 2.025), (2.7, 0, 2.4), (2.7, -0.25, 2.4), (3.3, -0.25, 2.4),
  3334. (3.3, 0, 2.4), (2.8, 0, 2.475), (2.8, -0.25, 2.475), (3.525, -0.25, 2.49375),
  3335. (3.525, 0, 2.49375), (2.9, 0, 2.475), (2.9, -0.15, 2.475), (3.45, -0.15, 2.5125),
  3336. (3.45, 0, 2.5125), (2.8, 0, 2.4), (2.8, -0.15, 2.4), (3.2, 0.15, 2.4), (3.2, 0, 2.4),
  3337. (0, 0, 3.15), (0.8, 0, 3.15), (0.8, -0.45, 3.15), (0.45, -0.8, 3.15), (0, -0.8, 3.15),
  3338. (0, 0, 2.85), (1.4, 0, 2.4), (1.4, -0.784, 2.4), (0.784, -1.4, 2.4), (0, -1.4, 2.4),
  3339. (0.4, 0, 2.55), (0.4, -0.224, 2.55), (0.224, -0.4, 2.55), (0, -0.4, 2.55), (1.3, 0, 2.55),
  3340. (1.3, -0.728, 2.55), (0.728, -1.3, 2.55), (0, -1.3, 2.55), (1.3, 0, 2.4), (1.3, -0.728, 2.4),
  3341. (0.728, -1.3, 2.4), (0, -1.3, 2.4), (0, 0, 0), (1.425, -0.798, 0), (1.5, 0, 0.075), (1.425, 0, 0),
  3342. (0.798, -1.425, 0), (0, -1.5, 0.075), (0, -1.425, 0), (1.5, -0.84, 0.075), (0.84, -1.5, 0.075));
  3343. Tex: array[0..1, 0..1, 0..1] of Single =
  3344. (((0, 0), (1, 0)), ((0, 1), (1, 1)));
  3345. var
  3346. P, Q, R, S: array[0..3, 0..3, 0..2] of Single;
  3347. I, J, K, L, GRD: Integer;
  3348. begin
  3349. if FGrid < 2 then
  3350. FGrid := 2;
  3351. GRD := FGrid;
  3352. rci.GLStates.InvertFrontFace;
  3353. gl.Enable(GL_AUTO_NORMAL);
  3354. gl.Enable(GL_MAP2_VERTEX_3);
  3355. gl.Enable(GL_MAP2_TEXTURE_COORD_2);
  3356. for I := 0 to 9 do
  3357. begin
  3358. for J := 0 to 3 do
  3359. begin
  3360. for K := 0 to 3 do
  3361. begin
  3362. for L := 0 to 2 do
  3363. begin
  3364. P[J, K, L] := CPData[PatchData[I, J * 4 + K], L];
  3365. Q[J, K, L] := CPData[PatchData[I, J * 4 + (3 - K)], L];
  3366. if L = 1 then
  3367. Q[J, K, L] := -Q[J, K, L];
  3368. if I < 6 then
  3369. begin
  3370. R[J, K, L] := CPData[PatchData[I, J * 4 + (3 - K)], L];
  3371. if L = 0 then
  3372. R[J, K, L] := -R[J, K, L];
  3373. S[J, K, L] := CPData[PatchData[I, J * 4 + K], L];
  3374. if L < 2 then
  3375. S[J, K, L] := -S[J, K, L];
  3376. end;
  3377. end;
  3378. end;
  3379. end;
  3380. gl.MapGrid2f(GRD, 0, 1, GRD, 0, 1);
  3381. gl.Map2f(GL_MAP2_TEXTURE_COORD_2, 0, 1, 2, 2, 0, 1, 4, 2, @Tex[0, 0, 0]);
  3382. gl.Map2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, @P[0, 0, 0]);
  3383. gl.EvalMesh2(GL_FILL, 0, GRD, 0, GRD);
  3384. gl.Map2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, @Q[0, 0, 0]);
  3385. gl.EvalMesh2(GL_FILL, 0, GRD, 0, GRD);
  3386. if I < 6 then
  3387. begin
  3388. gl.Map2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, @R[0, 0, 0]);
  3389. gl.EvalMesh2(GL_FILL, 0, GRD, 0, GRD);
  3390. gl.Map2f(GL_MAP2_VERTEX_3, 0, 1, 3, 4, 0, 1, 12, 4, @S[0, 0, 0]);
  3391. gl.EvalMesh2(GL_FILL, 0, GRD, 0, GRD);
  3392. end;
  3393. end;
  3394. gl.Disable(GL_AUTO_NORMAL);
  3395. gl.Disable(GL_MAP2_VERTEX_3);
  3396. gl.Disable(GL_MAP2_TEXTURE_COORD_2);
  3397. rci.GLStates.InvertFrontFace;
  3398. end;
  3399. procedure TGLTeapot.DoRender(var ARci: TGLRenderContextInfo;
  3400. ARenderSelf, ARenderChildren: Boolean);
  3401. const
  3402. M: TGLMatrix = (
  3403. X:(X:0.150000005960464; Y:0; Z:0; W:0);
  3404. Y:(X:0; Y:-6.55670850946422e-09; Z:-0.150000005960464; W:0);
  3405. Z:(X:0; Y:0.150000005960464; Z:-6.55670850946422e-09; W:0);
  3406. W:(X:0; Y:1.63917712736605e-09; Z:0.0375000014901161; W:1));
  3407. begin
  3408. // start rendering self
  3409. if ARenderSelf then
  3410. begin
  3411. with ARci.PipelineTransformation do
  3412. SetModelMatrix(MatrixMultiply(M, ModelMatrix^));
  3413. if ARci.ignoreMaterials then
  3414. if (osDirectDraw in ObjectStyle) or ARci.amalgamating then
  3415. BuildList(ARci)
  3416. else
  3417. ARci.GLStates.CallList(GetHandle(ARci))
  3418. else
  3419. begin
  3420. Material.Apply(ARci);
  3421. repeat
  3422. if (osDirectDraw in ObjectStyle) or ARci.amalgamating then
  3423. BuildList(ARci)
  3424. else
  3425. ARci.GLStates.CallList(GetHandle(ARci));
  3426. until not Material.UnApply(ARci);
  3427. end;
  3428. end;
  3429. // start rendering children (if any)
  3430. if ARenderChildren then
  3431. Self.RenderChildren(0, Count - 1, ARci);
  3432. end;
  3433. // -------------------------------------------------------------
  3434. initialization
  3435. // -------------------------------------------------------------
  3436. RegisterClasses(
  3437. [TGLDodecahedron, TGLIcosahedron, TGLHexahedron, TGLOctahedron, TGLTetrahedron,
  3438. TGLCylinder, TGLCone, TGLTorus, TGLDisk, TGLArrowLine, TGLAnnulus,
  3439. TGLFrustrum, TGLPolygon, TGLCapsule, TGLArrowArc, TGLTeapot]);
  3440. end.