GLS.GeomObjects.pas 111 KB

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