GLS.Objects.pas 99 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640
  1. //
  2. // The graphics engine GLScene
  3. //
  4. unit GLS.Objects;
  5. (*
  6. Implementation of basic scene objects plus some management routines.
  7. The registered classes are:
  8. [TGLSphere, TGLCube, TGLPlane, TGLSprite, TGLPoints,
  9. TGLDummyCube, TGLLines, TGLSuperellipsoid]
  10. All objects declared in this unit are part of the basic GLScene package,
  11. these are only simple objects and should be kept simple and lightweight.
  12. More complex or more specialized versions should be placed in dedicated
  13. units where they can grow and prosper untammed. "Generic" geometrical
  14. objects can be found in GLS.GeomObjects unit.
  15. *)
  16. interface
  17. {$I Stage.Defines.inc}
  18. uses
  19. Winapi.OpenGL,
  20. Winapi.OpenGLext,
  21. System.Types,
  22. System.Classes,
  23. System.SysUtils,
  24. System.Math,
  25. GLS.OpenGLAdapter,
  26. Stage.OpenGLTokens,
  27. Stage.VectorGeometry,
  28. Stage.VectorTypes,
  29. GLS.PersistentClasses,
  30. GLS.BaseClasses,
  31. GLS.Coordinates,
  32. Stage.Spline,
  33. GLS.VectorLists,
  34. Stage.PipelineTransform,
  35. GLS.Scene,
  36. GLS.Context,
  37. GLS.Silhouette,
  38. GLS.Color,
  39. GLS.RenderContextInfo,
  40. GLS.Nodes,
  41. GLS.XOpenGL,
  42. GLS.State;
  43. const
  44. cDefaultPointSize: Single = 1.0;
  45. type
  46. TGLVisibilityDeterminationEvent = function(Sender: TObject;
  47. var rci: TGLRenderContextInfo): Boolean of object;
  48. PGLVertexRec = ^TGLVertexRec;
  49. TGLVertexRec = record
  50. Position: TVector3f;
  51. Normal: TVector3f;
  52. Binormal: TVector3f;
  53. Tangent: TVector3f;
  54. TexCoord: TVector2f;
  55. end;
  56. (* A simple cube, invisible at run-time.
  57. This is a usually non-visible object -except at design-time- used for
  58. building hierarchies or groups, when some kind of joint or movement
  59. mechanism needs be described, you can use DummyCubes.
  60. DummyCube's barycenter is its children's barycenter.
  61. The DummyCube can optionnally amalgamate all its children into a single
  62. display list (see Amalgamate property). *)
  63. TGLDummyCube = class(TGLCameraInvariantObject)
  64. private
  65. FCubeSize: TGLFloat;
  66. FEdgeColor: TGLColor;
  67. FVisibleAtRunTime, FAmalgamate: Boolean;
  68. FGroupList: TGLListHandle;
  69. FOnVisibilityDetermination: TGLVisibilityDeterminationEvent;
  70. protected
  71. procedure SetCubeSize(const val: TGLFloat); inline;
  72. procedure SetEdgeColor(const val: TGLColor); inline;
  73. procedure SetVisibleAtRunTime(const val: Boolean); inline;
  74. procedure SetAmalgamate(const val: Boolean); inline;
  75. public
  76. constructor Create(AOwner: TComponent); override;
  77. destructor Destroy; override;
  78. procedure Assign(Source: TPersistent); override;
  79. function AxisAlignedDimensionsUnscaled: TGLVector; override;
  80. function RayCastIntersect(const rayStart, rayVector: TGLVector;
  81. intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil)
  82. : Boolean; override;
  83. procedure BuildList(var rci: TGLRenderContextInfo); override;
  84. procedure DoRender(var rci: TGLRenderContextInfo;
  85. renderSelf, renderChildren: Boolean); override;
  86. procedure StructureChanged; override;
  87. function BarycenterAbsolutePosition: TGLVector; override;
  88. published
  89. property CubeSize: TGLFloat read FCubeSize write SetCubeSize;
  90. property EdgeColor: TGLColor read FEdgeColor write SetEdgeColor;
  91. (* If true the dummycube's edges will be visible at runtime.
  92. The default behaviour of the dummycube is to be visible at design-time
  93. only, and invisible at runtime. *)
  94. property VisibleAtRunTime: Boolean read FVisibleAtRunTime
  95. write SetVisibleAtRunTime default False;
  96. (* Amalgamate the dummy's children in a single OpenGL entity.
  97. This activates a special rendering mode, which will compile
  98. the rendering of all of the dummycube's children objects into a
  99. single display list. This may provide a significant speed up in some
  100. situations, however, this means that changes to the children will
  101. be ignored until you call StructureChanged on the dummy cube.
  102. Some objects, that have their own display list management, may not
  103. be compatible with this behaviour. This will also prevents sorting
  104. and culling to operate as usual.
  105. In short, this features is best used for static, non-transparent
  106. geometry, or when the point of view won't change over a large
  107. number of frames. *)
  108. property Amalgamate: Boolean read FAmalgamate write SetAmalgamate
  109. default False;
  110. (* Camera Invariance Options.
  111. These options allow to "deactivate" sensitivity to camera, f.i. by
  112. centering the object on the camera or ignoring camera orientation. *)
  113. property CamInvarianceMode default cimNone;
  114. (* Event for custom visibility determination.
  115. Event handler should return True if the dummycube and its children
  116. are to be considered visible for the current render. *)
  117. property OnVisibilityDetermination: TGLVisibilityDeterminationEvent
  118. read FOnVisibilityDetermination write FOnVisibilityDetermination;
  119. end;
  120. TGLPlaneStyle = (psSingleQuad, psTileTexture);
  121. TGLPlaneStyles = set of TGLPlaneStyle;
  122. (* A simple plane object.
  123. Note that a plane is always made of a single quad (two triangles) and the
  124. tiling is only applied to texture coordinates. *)
  125. TGLPlane = class(TGLSceneObject)
  126. private
  127. FXOffset, FYOffset: TGLFloat;
  128. FXScope, FYScope: TGLFloat;
  129. FWidth, FHeight: TGLFloat;
  130. FXTiles, FYTiles: Cardinal;
  131. FStyle: TGLPlaneStyles;
  132. FMesh: array of array of TGLVertexRec;
  133. protected
  134. procedure SetHeight(const aValue: Single);
  135. procedure SetWidth(const aValue: Single);
  136. procedure SetXOffset(const Value: TGLFloat);
  137. procedure SetXScope(const Value: TGLFloat);
  138. function StoreXScope: Boolean;
  139. procedure SetXTiles(const Value: Cardinal);
  140. procedure SetYOffset(const Value: TGLFloat);
  141. procedure SetYScope(const Value: TGLFloat);
  142. function StoreYScope: Boolean;
  143. procedure SetYTiles(const Value: Cardinal);
  144. procedure SetStyle(const val: TGLPlaneStyles);
  145. public
  146. constructor Create(AOwner: TComponent); override;
  147. procedure Assign(Source: TPersistent); override;
  148. procedure BuildList(var rci: TGLRenderContextInfo); override;
  149. function GenerateSilhouette(const silhouetteParameters
  150. : TGLSilhouetteParameters): TGLSilhouette; override;
  151. function AxisAlignedDimensionsUnscaled: TGLVector; override;
  152. function RayCastIntersect(const rayStart, rayVector: TGLVector;
  153. intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil)
  154. : Boolean; override;
  155. (* Computes the screen coordinates of the smallest rectangle encompassing the plane.
  156. Returned extents are NOT limited to any physical screen extents. *)
  157. function ScreenRect(aBuffer: TGLSceneBuffer): TRect;
  158. (* Computes the signed distance to the point.
  159. Point coordinates are expected in absolute coordinates. *)
  160. function PointDistance(const aPoint: TGLVector): Single;
  161. published
  162. property Height: TGLFloat read FHeight write SetHeight;
  163. property Width: TGLFloat read FWidth write SetWidth;
  164. property XOffset: TGLFloat read FXOffset write SetXOffset;
  165. property XScope: TGLFloat read FXScope write SetXScope stored StoreXScope;
  166. property XTiles: Cardinal read FXTiles write SetXTiles default 1;
  167. property YOffset: TGLFloat read FYOffset write SetYOffset;
  168. property YScope: TGLFloat read FYScope write SetYScope stored StoreYScope;
  169. property YTiles: Cardinal read FYTiles write SetYTiles default 1;
  170. property Style: TGLPlaneStyles read FStyle write SetStyle
  171. default [psSingleQuad, psTileTexture];
  172. end;
  173. (* A rectangular area, perspective projected, but always facing the camera.
  174. A TGLSprite is perspective projected and as such is scaled with distance,
  175. if you want a 2D sprite that does not get scaled, see TGLHUDSprite. *)
  176. TGLSprite = class(TGLSceneObject)
  177. private
  178. FWidth: TGLFloat;
  179. FHeight: TGLFloat;
  180. FRotation: TGLFloat;
  181. FAlphaChannel: Single;
  182. FMirrorU, FMirrorV: Boolean;
  183. protected
  184. procedure SetWidth(const val: TGLFloat);
  185. procedure SetHeight(const val: TGLFloat);
  186. procedure SetRotation(const val: TGLFloat);
  187. procedure SetAlphaChannel(const val: Single);
  188. function StoreAlphaChannel: Boolean;
  189. procedure SetMirrorU(const val: Boolean);
  190. procedure SetMirrorV(const val: Boolean);
  191. public
  192. constructor Create(AOwner: TComponent); override;
  193. procedure Assign(Source: TPersistent); override;
  194. procedure BuildList(var rci: TGLRenderContextInfo); override;
  195. function AxisAlignedDimensionsUnscaled: TGLVector; override;
  196. procedure SetSize(const Width, Height: TGLFloat);
  197. // Set width and height to "size"
  198. procedure SetSquareSize(const Size: TGLFloat);
  199. published
  200. // Sprite Width in 3D world units.
  201. property Width: TGLFloat read FWidth write SetWidth;
  202. // Sprite Height in 3D world units.
  203. property Height: TGLFloat read FHeight write SetHeight;
  204. (* This the ON-SCREEN rotation of the sprite.
  205. Rotatation=0 is handled faster. *)
  206. property Rotation: TGLFloat read FRotation write SetRotation;
  207. // If different from 1, this value will replace that of Diffuse.Alpha
  208. property AlphaChannel: Single read FAlphaChannel write SetAlphaChannel
  209. stored StoreAlphaChannel;
  210. // Reverses the texture coordinates in the U and V direction to mirror the texture.
  211. property MirrorU: Boolean read FMirrorU write SetMirrorU default False;
  212. property MirrorV: Boolean read FMirrorV write SetMirrorV default False;
  213. end;
  214. TGLPointStyle = (psSquare, psRound, psSmooth, psSmoothAdditive,
  215. psSquareAdditive);
  216. (* Point parameters as in ARB_point_parameters.
  217. Make sure to read the ARB_point_parameters spec if you want to understand
  218. what each parameter does. *)
  219. TGLPointParameters = class(TGLUpdateAbleObject)
  220. private
  221. FEnabled: Boolean;
  222. FMinSize, FMaxSize: Single;
  223. FFadeTresholdSize: Single;
  224. FDistanceAttenuation: TGLCoordinates;
  225. protected
  226. procedure SetEnabled(const val: Boolean);
  227. procedure SetMinSize(const val: Single);
  228. procedure SetMaxSize(const val: Single);
  229. procedure SetFadeTresholdSize(const val: Single);
  230. procedure SetDistanceAttenuation(const val: TGLCoordinates);
  231. procedure DefineProperties(Filer: TFiler); override;
  232. procedure ReadData(Stream: TStream);
  233. procedure WriteData(Stream: TStream);
  234. public
  235. constructor Create(AOwner: TPersistent); override;
  236. destructor Destroy; override;
  237. procedure Assign(Source: TPersistent); override;
  238. procedure Apply;
  239. procedure UnApply;
  240. published
  241. property Enabled: Boolean read FEnabled write SetEnabled default False;
  242. property MinSize: Single read FMinSize write SetMinSize stored False;
  243. property MaxSize: Single read FMaxSize write SetMaxSize stored False;
  244. property FadeTresholdSize: Single read FFadeTresholdSize
  245. write SetFadeTresholdSize stored False;
  246. // Components XYZ are for constant, linear and quadratic attenuation.
  247. property DistanceAttenuation: TGLCoordinates read FDistanceAttenuation
  248. write SetDistanceAttenuation;
  249. end;
  250. (* Renders a set of non-transparent colored points.
  251. The points positions and their color are defined through the Positions
  252. and Colors properties *)
  253. TGLPoints = class(TGLImmaterialSceneObject)
  254. private
  255. FPositions: TGLAffineVectorList;
  256. FColors: TGLVectorList;
  257. FSize: Single;
  258. FStyle: TGLPointStyle;
  259. FPointParameters: TGLPointParameters;
  260. FStatic, FNoZWrite: Boolean;
  261. protected
  262. function StoreSize: Boolean; inline;
  263. procedure SetNoZWrite(const val: Boolean);
  264. procedure SetStatic(const val: Boolean);
  265. procedure SetSize(const val: Single);
  266. procedure SetPositions(const val: TGLAffineVectorList); inline;
  267. procedure SetColors(const val: TGLVectorList);
  268. procedure SetStyle(const val: TGLPointStyle);
  269. procedure SetPointParameters(const val: TGLPointParameters);
  270. public
  271. constructor Create(AOwner: TComponent); override;
  272. destructor Destroy; override;
  273. procedure Assign(Source: TPersistent); override;
  274. procedure BuildList(var rci: TGLRenderContextInfo); override;
  275. // Points positions. If empty, a single point is assumed at (0, 0, 0)
  276. property Positions: TGLAffineVectorList read FPositions write SetPositions;
  277. (* Defines the points colors:
  278. if empty, point color will be opaque white
  279. if contains a single color, all points will use that color
  280. if contains N colors, the first N points (at max) will be rendered
  281. using the corresponding colors *)
  282. property Colors: TGLVectorList read FColors write SetColors;
  283. published
  284. // If true points do not write their Z to the depth buffer.
  285. property NoZWrite: Boolean read FNoZWrite write SetNoZWrite;
  286. (* Tells the component if point coordinates are static.
  287. If static, changes to the positions should be notified via an
  288. explicit StructureChanged call, or may not refresh.
  289. Static sets of points may render faster than dynamic ones. *)
  290. property Static: Boolean read FStatic write SetStatic;
  291. // Point size, all points have a fixed size.
  292. property Size: Single read FSize write SetSize stored StoreSize;
  293. // Points style.
  294. property Style: TGLPointStyle read FStyle write SetStyle default psSquare;
  295. (* Point parameters as of ARB_point_parameters.
  296. Allows to vary the size and transparency of points depending
  297. on their distance to the observer. *)
  298. property PointParameters: TGLPointParameters read FPointParameters
  299. write SetPointParameters;
  300. end;
  301. // Possible aspects for the nodes of a TLine.
  302. TGLLineNodesAspect = (lnaInvisible, lnaAxes, lnaCube);
  303. // Available spline modes for a TLine.
  304. TGLLineSplineMode = (lsmLines, lsmCubicSpline, lsmBezierSpline, lsmNURBSCurve,
  305. lsmSegments, lsmLoop);
  306. // Specialized Node for use in a TGLLines objects. Adds a Color property (TGLColor) }
  307. TGLLinesNode = class(TGLNode)
  308. private
  309. FColor: TGLColor;
  310. protected
  311. procedure SetColor(const val: TGLColor);
  312. procedure OnColorChange(Sender: TObject);
  313. function StoreColor: Boolean;
  314. public
  315. constructor Create(Collection: TCollection); override;
  316. destructor Destroy; override;
  317. procedure Assign(Source: TPersistent); override;
  318. published
  319. (* The node color.
  320. Can also defined the line color (interpolated between nodes) if
  321. loUseNodeColorForLines is set (in TGLLines). *)
  322. property Color: TGLColor read FColor write SetColor stored StoreColor;
  323. end;
  324. (* Specialized collection for Nodes in a TGLLines objects. Stores TGLLinesNode items *)
  325. TGLLinesNodes = class(TGLNodes)
  326. public
  327. constructor Create(AOwner: TComponent); overload;
  328. procedure NotifyChange; override;
  329. end;
  330. (* Base class for line objects. Introduces line style properties (width, color...) *)
  331. TGLLineBase = class(TGLImmaterialSceneObject)
  332. private
  333. FLineColor: TGLColor;
  334. FLinePattern: TGLushort;
  335. FLineWidth: Single;
  336. FAntiAliased: Boolean;
  337. protected
  338. procedure SetLineColor(const Value: TGLColor);
  339. procedure SetLinePattern(const Value: TGLushort);
  340. procedure SetLineWidth(const val: Single);
  341. function StoreLineWidth: Boolean; inline;
  342. procedure SetAntiAliased(const val: Boolean);
  343. (* Setup OpenGL states according to line style.
  344. You must call RestoreLineStyle after drawing your lines.
  345. You may use nested calls with SetupLineStyle/RestoreLineStyle *)
  346. procedure SetupLineStyle(var rci: TGLRenderContextInfo);
  347. public
  348. constructor Create(AOwner: TComponent); override;
  349. destructor Destroy; override;
  350. procedure Assign(Source: TPersistent); override;
  351. procedure NotifyChange(Sender: TObject); override;
  352. published
  353. (* Indicates if OpenGL should smooth line edges.
  354. Smoothed lines looks better but are poorly implemented in most OpenGL
  355. drivers and take *lots* of rendering time *)
  356. property AntiAliased: Boolean read FAntiAliased write SetAntiAliased
  357. default False;
  358. // Default color of the lines.
  359. property LineColor: TGLColor read FLineColor write SetLineColor;
  360. (* Bitwise line pattern.
  361. For instance $FFFF (65535) is a white line (stipple disabled), $0000
  362. is a black line, $CCCC is the stipple used in axes and dummycube, etc. *)
  363. property LinePattern: TGLushort read FLinePattern write SetLinePattern
  364. default $FFFF;
  365. // Default width of the lines.
  366. property LineWidth: Single read FLineWidth write SetLineWidth
  367. stored StoreLineWidth;
  368. property Visible;
  369. end;
  370. // Class that defines lines via a series of nodes. Base class, does not render anything
  371. TGLNodedLines = class(TGLLineBase)
  372. private
  373. FNodes: TGLLinesNodes;
  374. FNodesAspect: TGLLineNodesAspect;
  375. FNodeColor: TGLColor;
  376. FNodeSize: Single;
  377. FOldNodeColor: TGLColorVector;
  378. protected
  379. procedure SetNodesAspect(const Value: TGLLineNodesAspect);
  380. procedure SetNodeColor(const Value: TGLColor);
  381. procedure OnNodeColorChanged(Sender: TObject);
  382. procedure SetNodes(const aNodes: TGLLinesNodes);
  383. procedure SetNodeSize(const val: Single);
  384. function StoreNodeSize: Boolean;
  385. procedure DrawNode(var rci: TGLRenderContextInfo; X, Y, Z: Single;
  386. Color: TGLColor);
  387. public
  388. constructor Create(AOwner: TComponent); override;
  389. destructor Destroy; override;
  390. procedure Assign(Source: TPersistent); override;
  391. function AxisAlignedDimensionsUnscaled: TGLVector; override;
  392. procedure AddNode(const coords: TGLCoordinates); overload;
  393. procedure AddNode(const X, Y, Z: TGLFloat); overload;
  394. procedure AddNode(const Value: TGLVector); overload;
  395. procedure AddNode(const Value: TAffineVector); overload;
  396. published
  397. // Default color for nodes. lnaInvisible and lnaAxes ignore this setting
  398. property NodeColor: TGLColor read FNodeColor write SetNodeColor;
  399. // The nodes list.
  400. property Nodes: TGLLinesNodes read FNodes write SetNodes;
  401. (* Default aspect of line nodes.
  402. May help you materialize nodes, segments and control points. *)
  403. property NodesAspect: TGLLineNodesAspect read FNodesAspect
  404. write SetNodesAspect default lnaAxes;
  405. // Size for the various node aspects.
  406. property NodeSize: Single read FNodeSize write SetNodeSize
  407. stored StoreNodeSize;
  408. end;
  409. TGLLinesOption = (loUseNodeColorForLines, loColorLogicXor);
  410. TGLLinesOptions = set of TGLLinesOption;
  411. (* Set of 3D line segments.
  412. You define a 3D Line by adding its nodes in the "Nodes" property. The line
  413. may be rendered as a set of segment or as a curve (nodes then act as spline
  414. control points).
  415. Alternatively, you can also use it to render a set of spacial nodes (points
  416. in space), just make the lines transparent and the nodes visible by picking
  417. the node aspect that suits you. *)
  418. TGLLines = class(TGLNodedLines)
  419. private
  420. FDivision: Integer;
  421. FSplineMode: TGLLineSplineMode;
  422. FOptions: TGLLinesOptions;
  423. FNURBSOrder: Integer;
  424. FNURBSTolerance: Single;
  425. FNURBSKnots: TGLSingleList;
  426. protected
  427. procedure SetSplineMode(const val: TGLLineSplineMode);
  428. procedure SetDivision(const Value: Integer);
  429. procedure SetOptions(const val: TGLLinesOptions);
  430. procedure SetNURBSOrder(const val: Integer);
  431. procedure SetNURBSTolerance(const val: Single);
  432. public
  433. constructor Create(AOwner: TComponent); override;
  434. destructor Destroy; override;
  435. procedure Assign(Source: TPersistent); override;
  436. procedure BuildList(var rci: TGLRenderContextInfo); override;
  437. property NURBSKnots: TGLSingleList read FNURBSKnots;
  438. property NURBSOrder: Integer read FNURBSOrder write SetNURBSOrder;
  439. property NURBSTolerance: Single read FNURBSTolerance
  440. write SetNURBSTolerance;
  441. published
  442. (* Number of divisions for each segment in spline modes.
  443. Minimum 1 (disabled), ignored in lsmLines mode. *)
  444. property Division: Integer read FDivision write SetDivision default 10;
  445. // Default spline drawing mode.
  446. property SplineMode: TGLLineSplineMode read FSplineMode write SetSplineMode
  447. default lsmLines;
  448. (* Rendering options for the line.
  449. loUseNodeColorForLines: if set lines will be drawn using node
  450. colors (and color interpolation between nodes), if not, LineColor
  451. will be used (single color).
  452. loColorLogicXor: enable logic operation for color of XOR type. *)
  453. property Options: TGLLinesOptions read FOptions write SetOptions;
  454. end;
  455. TGLCubePart = (cpTop, cpBottom, cpFront, cpBack, cpLeft, cpRight);
  456. TGLCubeParts = set of TGLCubePart;
  457. (* A simple cube object.
  458. This cube use the same material for each of its faces, ie. all faces look
  459. the same. If you want a multi-material cube, use a mesh in conjunction
  460. with a TGLFreeForm and a material library.
  461. Ref: https://mathworld.wolfram.com/Cube.html *)
  462. TGLCube = class(TGLSceneObject)
  463. private
  464. FCubeSize: TAffineVector;
  465. FParts: TGLCubeParts;
  466. FNormalDirection: TGLNormalDirection;
  467. function GetCubeWHD(const Index: Integer): TGLFloat; inline;
  468. procedure SetCubeWHD(Index: Integer; aValue: TGLFloat); inline;
  469. procedure SetParts(aValue: TGLCubeParts); inline;
  470. procedure SetNormalDirection(aValue: TGLNormalDirection); inline;
  471. protected
  472. procedure DefineProperties(Filer: TFiler); override;
  473. procedure ReadData(Stream: TStream); inline;
  474. procedure WriteData(Stream: TStream); inline;
  475. public
  476. constructor Create(AOwner: TComponent); override;
  477. function GenerateSilhouette(const silhouetteParameters
  478. : TGLSilhouetteParameters): TGLSilhouette; override;
  479. procedure BuildList(var rci: TGLRenderContextInfo); override;
  480. procedure Assign(Source: TPersistent); override;
  481. function AxisAlignedDimensionsUnscaled: TGLVector; override;
  482. function RayCastIntersect(const rayStart, rayVector: TGLVector;
  483. intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil)
  484. : Boolean; override;
  485. published
  486. property CubeWidth: TGLFloat index 0 read GetCubeWHD write SetCubeWHD
  487. stored False;
  488. property CubeHeight: TGLFloat index 1 read GetCubeWHD write SetCubeWHD
  489. stored False;
  490. property CubeDepth: TGLFloat index 2 read GetCubeWHD write SetCubeWHD
  491. stored False;
  492. property NormalDirection: TGLNormalDirection read FNormalDirection
  493. write SetNormalDirection default ndOutside;
  494. property Parts: TGLCubeParts read FParts write SetParts
  495. default [cpTop, cpBottom, cpFront, cpBack, cpLeft, cpRight];
  496. end;
  497. (* Determines how and if normals are smoothed.
  498. - nsFlat : facetted look
  499. - nsSmooth : smooth look
  500. - nsNone : unlighted rendering, usefull for decla texturing *)
  501. TGLNormalSmoothing = (nsFlat, nsSmooth, nsNone);
  502. (* Base class for quadric objects.
  503. Introduces some basic Quadric interaction functions (the actual quadric
  504. math is part of the GLU library). *)
  505. TGLQuadricObject = class(TGLSceneObject)
  506. private
  507. FNormals: TGLNormalSmoothing;
  508. FNormalDirection: TGLNormalDirection;
  509. protected
  510. procedure SetNormals(aValue: TGLNormalSmoothing);
  511. procedure SetNormalDirection(aValue: TGLNormalDirection);
  512. procedure SetupQuadricParams(quadric: PGLUquadricObj);
  513. procedure SetNormalQuadricOrientation(quadric: PGLUquadricObj);
  514. procedure SetInvertedQuadricOrientation(quadric: PGLUquadricObj);
  515. public
  516. constructor Create(AOwner: TComponent); override;
  517. procedure Assign(Source: TPersistent); override;
  518. published
  519. property Normals: TGLNormalSmoothing read FNormals write SetNormals
  520. default nsSmooth;
  521. property NormalDirection: TGLNormalDirection read FNormalDirection
  522. write SetNormalDirection default ndOutside;
  523. end;
  524. TGLAngleLimit180 = -90 .. 90;
  525. TGLAngleLimit360 = 0 .. 360;
  526. TGLCapType = (ctNone, ctCenter, ctFlat);
  527. (* A sphere object.
  528. The sphere can have to and bottom caps, as well as being just a slice of sphere.
  529. Ref: https://mathworld.wolfram.com/Sphere.html
  530. Ref: https://mathworld.wolfram.com/GeodesicDome.html *)
  531. TGLSphere = class(TGLQuadricObject)
  532. private
  533. FRadius: TGLFloat;
  534. FSlices, FStacks: TGLInt;
  535. FTop: TGLAngleLimit180;
  536. FBottom: TGLAngleLimit180;
  537. FStart: TGLAngleLimit360;
  538. FStop: TGLAngleLimit360;
  539. FTopCap, FBottomCap: TGLCapType;
  540. procedure SetBottom(aValue: TGLAngleLimit180);
  541. procedure SetBottomCap(aValue: TGLCapType);
  542. procedure SetRadius(const aValue: TGLFloat);
  543. procedure SetSlices(aValue: TGLInt);
  544. procedure SetStart(aValue: TGLAngleLimit360);
  545. procedure SetStop(aValue: TGLAngleLimit360);
  546. procedure SetStacks(aValue: TGLInt);
  547. procedure SetTop(aValue: TGLAngleLimit180);
  548. procedure SetTopCap(aValue: TGLCapType);
  549. public
  550. constructor Create(AOwner: TComponent); override;
  551. procedure Assign(Source: TPersistent); override;
  552. procedure BuildList(var rci: TGLRenderContextInfo); override;
  553. function AxisAlignedDimensionsUnscaled: TGLVector; override;
  554. function RayCastIntersect(const rayStart, rayVector: TGLVector;
  555. intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil)
  556. : Boolean; override;
  557. function GenerateSilhouette(const silhouetteParameters
  558. : TGLSilhouetteParameters): TGLSilhouette; override;
  559. published
  560. property Bottom: TGLAngleLimit180 read FBottom write SetBottom default -90;
  561. property BottomCap: TGLCapType read FBottomCap write SetBottomCap
  562. default ctNone;
  563. property Radius: TGLFloat read FRadius write SetRadius;
  564. property Slices: TGLInt read FSlices write SetSlices default 16;
  565. property Stacks: TGLInt read FStacks write SetStacks default 16;
  566. property Start: TGLAngleLimit360 read FStart write SetStart default 0;
  567. property Stop: TGLAngleLimit360 read FStop write SetStop default 360;
  568. property Top: TGLAngleLimit180 read FTop write SetTop default 90;
  569. property TopCap: TGLCapType read FTopCap write SetTopCap default ctNone;
  570. end;
  571. (* Base class for objects based on a polygon *)
  572. TGLPolygonBase = class(TGLSceneObject)
  573. private
  574. FDivision: Integer;
  575. FSplineMode: TGLLineSplineMode;
  576. protected
  577. FNodes: TGLNodes;
  578. procedure CreateNodes; dynamic;
  579. procedure SetSplineMode(const val: TGLLineSplineMode);
  580. procedure SetDivision(const Value: Integer);
  581. procedure SetNodes(const aNodes: TGLNodes);
  582. public
  583. constructor Create(AOwner: TComponent); override;
  584. destructor Destroy; override;
  585. procedure Assign(Source: TPersistent); override;
  586. procedure NotifyChange(Sender: TObject); override;
  587. procedure AddNode(const coords: TGLCoordinates); overload;
  588. procedure AddNode(const X, Y, Z: TGLFloat); overload;
  589. procedure AddNode(const Value: TGLVector); overload;
  590. procedure AddNode(const Value: TAffineVector); overload;
  591. published
  592. // The nodes list.
  593. property Nodes: TGLNodes read FNodes write SetNodes;
  594. (* Number of divisions for each segment in spline modes.
  595. Minimum 1 (disabled), ignored in lsmLines mode. *)
  596. property Division: Integer read FDivision write SetDivision default 10;
  597. (* Default spline drawing mode.
  598. This mode is used only for the curve, not for the rotation path. *)
  599. property SplineMode: TGLLineSplineMode read FSplineMode write SetSplineMode
  600. default lsmLines;
  601. end;
  602. (* A Superellipsoid object. The Superellipsoid can have top and bottom caps,
  603. as well as being just a slice of Superellipsoid.
  604. Ref: https://mathworld.wolfram.com/Superellipse.html *)
  605. TGLSuperellipsoid = class(TGLQuadricObject)
  606. private
  607. FRadius, FVCurve, FHCurve: TGLFloat;
  608. FSlices, FStacks: TGLInt;
  609. FTop: TGLAngleLimit180;
  610. FBottom: TGLAngleLimit180;
  611. FStart: TGLAngleLimit360;
  612. FStop: TGLAngleLimit360;
  613. FTopCap, FBottomCap: TGLCapType;
  614. procedure SetBottom(aValue: TGLAngleLimit180);
  615. procedure SetBottomCap(aValue: TGLCapType);
  616. procedure SetRadius(const aValue: TGLFloat);
  617. procedure SetVCurve(const aValue: TGLFloat);
  618. procedure SetHCurve(const aValue: TGLFloat);
  619. procedure SetSlices(aValue: TGLInt);
  620. procedure SetStart(aValue: TGLAngleLimit360);
  621. procedure SetStop(aValue: TGLAngleLimit360);
  622. procedure SetStacks(aValue: TGLInt);
  623. procedure SetTop(aValue: TGLAngleLimit180);
  624. procedure SetTopCap(aValue: TGLCapType);
  625. public
  626. constructor Create(AOwner: TComponent); override;
  627. procedure Assign(Source: TPersistent); override;
  628. procedure BuildList(var rci: TGLRenderContextInfo); override;
  629. function AxisAlignedDimensionsUnscaled: TGLVector; override;
  630. function RayCastIntersect(const rayStart, rayVector: TGLVector;
  631. intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil)
  632. : Boolean; override;
  633. function GenerateSilhouette(const silhouetteParameters
  634. : TGLSilhouetteParameters): TGLSilhouette; override;
  635. published
  636. property Bottom: TGLAngleLimit180 read FBottom write SetBottom default -90;
  637. property BottomCap: TGLCapType read FBottomCap write SetBottomCap
  638. default ctNone;
  639. property Radius: TGLFloat read FRadius write SetRadius;
  640. property VCurve: TGLFloat read FVCurve write SetVCurve;
  641. property HCurve: TGLFloat read FHCurve write SetHCurve;
  642. property Slices: TGLInt read FSlices write SetSlices default 16;
  643. property Stacks: TGLInt read FStacks write SetStacks default 16;
  644. property Start: TGLAngleLimit360 read FStart write SetStart default 0;
  645. property Stop: TGLAngleLimit360 read FStop write SetStop default 360;
  646. property Top: TGLAngleLimit180 read FTop write SetTop default 90;
  647. property TopCap: TGLCapType read FTopCap write SetTopCap default ctNone;
  648. end;
  649. // Issues for a unit-size cube stippled wireframe
  650. procedure CubeWireframeBuildList(var rci: TGLRenderContextInfo; Size: TGLFloat;
  651. Stipple: Boolean; const Color: TGLColorVector);
  652. const
  653. TangentAttributeName: PAnsiChar = 'Tangent';
  654. BinormalAttributeName: PAnsiChar = 'Binormal';
  655. // -------------------------------------------------------------
  656. implementation
  657. // -------------------------------------------------------------
  658. procedure CubeWireframeBuildList(var rci: TGLRenderContextInfo; Size: TGLFloat;
  659. Stipple: Boolean; const Color: TGLColorVector);
  660. var
  661. mi, ma: Single;
  662. begin
  663. {$IFDEF USE_OPENGL_DEBUG}
  664. if GL.GREMEDY_string_marker then
  665. gl.StringMarkerGREMEDY(22, 'CubeWireframeBuildList');
  666. {$ENDIF}
  667. rci.GLStates.Disable(stLighting);
  668. rci.GLStates.Enable(stLineSmooth);
  669. if Stipple then
  670. begin
  671. rci.GLStates.Enable(stLineStipple);
  672. rci.GLStates.Enable(stBlend);
  673. rci.GLStates.SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
  674. rci.GLStates.LineStippleFactor := 1;
  675. rci.GLStates.LineStipplePattern := $CCCC;
  676. end;
  677. rci.GLStates.LineWidth := 1;
  678. ma := 0.5 * Size;
  679. mi := -ma;
  680. gl.Color4fv(@Color);
  681. gl.Begin_(GL_LINE_STRIP);
  682. // front face
  683. gl.Vertex3f(ma, mi, mi);
  684. gl.Vertex3f(ma, ma, mi);
  685. gl.Vertex3f(ma, ma, ma);
  686. gl.Vertex3f(ma, mi, ma);
  687. gl.Vertex3f(ma, mi, mi);
  688. // partial up back face
  689. gl.Vertex3f(mi, mi, mi);
  690. gl.Vertex3f(mi, mi, ma);
  691. gl.Vertex3f(mi, ma, ma);
  692. gl.Vertex3f(mi, ma, mi);
  693. // right side low
  694. gl.Vertex3f(ma, ma, mi);
  695. gl.End_;
  696. gl.Begin_(GL_LINES);
  697. // right high
  698. gl.Vertex3f(ma, ma, ma);
  699. gl.Vertex3f(mi, ma, ma);
  700. // back low
  701. gl.Vertex3f(mi, mi, mi);
  702. gl.Vertex3f(mi, ma, mi);
  703. // left high
  704. gl.Vertex3f(ma, mi, ma);
  705. gl.Vertex3f(mi, mi, ma);
  706. gl.End_;
  707. end;
  708. // ------------------
  709. // ------------------ TGLDummyCube ------------------
  710. // ------------------
  711. constructor TGLDummyCube.Create(AOwner: TComponent);
  712. begin
  713. inherited;
  714. ObjectStyle := ObjectStyle + [osDirectDraw];
  715. FCubeSize := 1;
  716. FEdgeColor := TGLColor.Create(Self);
  717. FEdgeColor.Initialize(clrWhite);
  718. FGroupList := TGLListHandle.Create;
  719. CamInvarianceMode := cimNone;
  720. end;
  721. destructor TGLDummyCube.Destroy;
  722. begin
  723. FGroupList.Free;
  724. FEdgeColor.Free;
  725. inherited;
  726. end;
  727. procedure TGLDummyCube.Assign(Source: TPersistent);
  728. begin
  729. if Source is TGLDummyCube then
  730. begin
  731. FCubeSize := TGLDummyCube(Source).FCubeSize;
  732. FEdgeColor.Color := TGLDummyCube(Source).FEdgeColor.Color;
  733. FVisibleAtRunTime := TGLDummyCube(Source).FVisibleAtRunTime;
  734. NotifyChange(Self);
  735. end;
  736. inherited Assign(Source);
  737. end;
  738. function TGLDummyCube.AxisAlignedDimensionsUnscaled: TGLVector;
  739. begin
  740. Result.X := 0.5 * Abs(FCubeSize);
  741. Result.Y := Result.X;
  742. Result.Z := Result.X;
  743. Result.W := 0;
  744. end;
  745. function TGLDummyCube.RayCastIntersect(const rayStart, rayVector: TGLVector;
  746. intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil): Boolean;
  747. begin
  748. Result := False;
  749. end;
  750. procedure TGLDummyCube.BuildList(var rci: TGLRenderContextInfo);
  751. begin
  752. if (csDesigning in ComponentState) or (FVisibleAtRunTime) then
  753. CubeWireframeBuildList(rci, FCubeSize, True, EdgeColor.Color);
  754. end;
  755. procedure TGLDummyCube.DoRender(var rci: TGLRenderContextInfo;
  756. renderSelf, renderChildren: Boolean);
  757. begin
  758. if Assigned(FOnVisibilityDetermination) then
  759. if not FOnVisibilityDetermination(Self, rci) then
  760. Exit;
  761. if FAmalgamate and (not rci.amalgamating) then
  762. begin
  763. if FGroupList.Handle = 0 then
  764. begin
  765. FGroupList.AllocateHandle;
  766. Assert(FGroupList.Handle <> 0, 'Handle=0 for ' + ClassName);
  767. rci.GLStates.NewList(FGroupList.Handle, GL_COMPILE);
  768. rci.amalgamating := True;
  769. // try
  770. inherited;
  771. // finally
  772. rci.amalgamating := False;
  773. rci.GLStates.EndList;
  774. // end;
  775. end;
  776. rci.GLStates.CallList(FGroupList.Handle);
  777. end
  778. else
  779. begin
  780. // proceed as usual
  781. inherited;
  782. end;
  783. end;
  784. procedure TGLDummyCube.StructureChanged;
  785. begin
  786. if FAmalgamate then
  787. FGroupList.DestroyHandle;
  788. inherited;
  789. end;
  790. function TGLDummyCube.BarycenterAbsolutePosition: TGLVector;
  791. var
  792. i: Integer;
  793. begin
  794. if Count > 0 then
  795. begin
  796. Result := Children[0].BarycenterAbsolutePosition;
  797. for i := 1 to Count - 1 do
  798. Result := VectorAdd(Result, Children[i].BarycenterAbsolutePosition);
  799. ScaleVector(Result, 1 / Count);
  800. end
  801. else
  802. Result := AbsolutePosition;
  803. end;
  804. procedure TGLDummyCube.SetCubeSize(const val: TGLFloat);
  805. begin
  806. if val <> FCubeSize then
  807. begin
  808. FCubeSize := val;
  809. StructureChanged;
  810. end;
  811. end;
  812. procedure TGLDummyCube.SetEdgeColor(const val: TGLColor);
  813. begin
  814. if val <> FEdgeColor then
  815. begin
  816. FEdgeColor.Assign(val);
  817. StructureChanged;
  818. end;
  819. end;
  820. procedure TGLDummyCube.SetVisibleAtRunTime(const val: Boolean);
  821. begin
  822. if val <> FVisibleAtRunTime then
  823. begin
  824. FVisibleAtRunTime := val;
  825. StructureChanged;
  826. end;
  827. end;
  828. procedure TGLDummyCube.SetAmalgamate(const val: Boolean);
  829. begin
  830. if val <> FAmalgamate then
  831. begin
  832. FAmalgamate := val;
  833. if not val then
  834. FGroupList.DestroyHandle;
  835. inherited StructureChanged;
  836. end;
  837. end;
  838. // ------------------
  839. // ------------------ TGLPlane ------------------
  840. // ------------------
  841. constructor TGLPlane.Create(AOwner: TComponent);
  842. begin
  843. inherited Create(AOwner);
  844. FWidth := 1;
  845. FHeight := 1;
  846. FXTiles := 1;
  847. FYTiles := 1;
  848. FXScope := 1;
  849. FYScope := 1;
  850. ObjectStyle := ObjectStyle + [osDirectDraw];
  851. FStyle := [psSingleQuad, psTileTexture];
  852. end;
  853. procedure TGLPlane.Assign(Source: TPersistent);
  854. begin
  855. if Assigned(Source) and (Source is TGLPlane) then
  856. begin
  857. FWidth := TGLPlane(Source).FWidth;
  858. FHeight := TGLPlane(Source).FHeight;
  859. FXOffset := TGLPlane(Source).FXOffset;
  860. FXScope := TGLPlane(Source).FXScope;
  861. FXTiles := TGLPlane(Source).FXTiles;
  862. FYOffset := TGLPlane(Source).FYOffset;
  863. FYScope := TGLPlane(Source).FYScope;
  864. FYTiles := TGLPlane(Source).FYTiles;
  865. FStyle := TGLPlane(Source).FStyle;
  866. StructureChanged;
  867. end;
  868. inherited Assign(Source);
  869. end;
  870. function TGLPlane.AxisAlignedDimensionsUnscaled: TGLVector;
  871. begin
  872. Result.X := 0.5 * Abs(FWidth);
  873. Result.Y := 0.5 * Abs(FHeight);
  874. Result.Z := 0;
  875. end;
  876. function TGLPlane.RayCastIntersect(const rayStart, rayVector: TGLVector;
  877. intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil): Boolean;
  878. var
  879. locRayStart, locRayVector, ip: TGLVector;
  880. t: Single;
  881. begin
  882. locRayStart := AbsoluteToLocal(rayStart);
  883. locRayVector := AbsoluteToLocal(rayVector);
  884. if locRayStart.Z >= 0 then
  885. begin
  886. // ray start over plane
  887. if locRayVector.Z < 0 then
  888. begin
  889. t := locRayStart.Z / locRayVector.Z;
  890. ip.X := locRayStart.X - t * locRayVector.X;
  891. ip.Y := locRayStart.Y - t * locRayVector.Y;
  892. if (Abs(ip.X) <= 0.5 * Width) and (Abs(ip.Y) <= 0.5 * Height) then
  893. begin
  894. Result := True;
  895. if Assigned(intersectNormal) then
  896. intersectNormal^ := AbsoluteDirection;
  897. end
  898. else
  899. Result := False;
  900. end
  901. else
  902. Result := False;
  903. end
  904. else
  905. begin
  906. // ray start below plane
  907. if locRayVector.Z > 0 then
  908. begin
  909. t := locRayStart.Z / locRayVector.Z;
  910. ip.X := locRayStart.X - t * locRayVector.X;
  911. ip.Y := locRayStart.Y - t * locRayVector.Y;
  912. if (Abs(ip.X) <= 0.5 * Width) and (Abs(ip.Y) <= 0.5 * Height) then
  913. begin
  914. Result := True;
  915. if Assigned(intersectNormal) then
  916. intersectNormal^ := VectorNegate(AbsoluteDirection);
  917. end
  918. else
  919. Result := False;
  920. end
  921. else
  922. Result := False;
  923. end;
  924. if Result and Assigned(intersectPoint) then
  925. begin
  926. ip.Z := 0;
  927. ip.W := 1;
  928. intersectPoint^ := LocalToAbsolute(ip);
  929. end;
  930. end;
  931. function TGLPlane.GenerateSilhouette(const silhouetteParameters
  932. : TGLSilhouetteParameters): TGLSilhouette;
  933. var
  934. hw, hh: Single;
  935. begin
  936. Result := TGLSilhouette.Create;
  937. hw := FWidth * 0.5;
  938. hh := FHeight * 0.5;
  939. with Result.vertices do
  940. begin
  941. AddPoint(hw, hh);
  942. AddPoint(hw, -hh);
  943. AddPoint(-hw, -hh);
  944. AddPoint(-hw, hh);
  945. end;
  946. with Result.Indices do
  947. begin
  948. Add(0, 1);
  949. Add(1, 2);
  950. Add(2, 3);
  951. Add(3, 0);
  952. end;
  953. if silhouetteParameters.CappingRequired then
  954. with Result.CapIndices do
  955. begin
  956. Add(0, 1, 2);
  957. Add(2, 3, 0);
  958. end;
  959. end;
  960. procedure TGLPlane.BuildList(var rci: TGLRenderContextInfo);
  961. procedure EmitVertex(ptr: PGLVertexRec); inline;
  962. begin
  963. xgl.TexCoord2fv(@ptr^.TexCoord);
  964. gl.Vertex3fv(@ptr^.Position);
  965. end;
  966. var
  967. hw, hh, posXFact, posYFact, pX, pY1: TGLFloat;
  968. tx0, tx1, ty0, ty1, texSFact, texTFact: TGLFloat;
  969. texS, texT1: TGLFloat;
  970. X, Y: Integer;
  971. TanLoc, BinLoc: Integer;
  972. pVertex: PGLVertexRec;
  973. begin
  974. hw := FWidth * 0.5;
  975. hh := FHeight * 0.5;
  976. gl.Normal3fv(@ZVector);
  977. if GL.ARB_shader_objects and (rci.GLStates.CurrentProgram > 0) then
  978. begin
  979. TanLoc := gl.GetAttribLocation(rci.GLStates.CurrentProgram,
  980. TangentAttributeName);
  981. BinLoc := gl.GetAttribLocation(rci.GLStates.CurrentProgram,
  982. BinormalAttributeName);
  983. if TanLoc > -1 then
  984. gl.VertexAttrib3fv(TanLoc, @XVector);
  985. if BinLoc > -1 then
  986. gl.VertexAttrib3fv(BinLoc, @YVector);
  987. end;
  988. // determine tex coords extents
  989. if psTileTexture in FStyle then
  990. begin
  991. tx0 := FXOffset;
  992. tx1 := FXTiles * FXScope + FXOffset;
  993. ty0 := FYOffset;
  994. ty1 := FYTiles * FYScope + FYOffset;
  995. end
  996. else
  997. begin
  998. tx0 := 0;
  999. ty0 := tx0;
  1000. tx1 := FXScope;
  1001. ty1 := FYScope;
  1002. end;
  1003. if psSingleQuad in FStyle then
  1004. begin
  1005. // single quad plane
  1006. gl.Begin_(GL_TRIANGLES);
  1007. xgl.TexCoord2f(tx1, ty1);
  1008. gl.Vertex2f(hw, hh);
  1009. xgl.TexCoord2f(tx0, ty1);
  1010. gl.Vertex2f(-hw, hh);
  1011. xgl.TexCoord2f(tx0, ty0);
  1012. gl.Vertex2f(-hw, -hh);
  1013. gl.Vertex2f(-hw, -hh);
  1014. xgl.TexCoord2f(tx1, ty0);
  1015. gl.Vertex2f(hw, -hh);
  1016. xgl.TexCoord2f(tx1, ty1);
  1017. gl.Vertex2f(hw, hh);
  1018. gl.End_;
  1019. Exit;
  1020. end
  1021. else
  1022. begin
  1023. // multi-quad plane (actually built from tri-strips)
  1024. texSFact := (tx1 - tx0) / FXTiles;
  1025. texTFact := (ty1 - ty0) / FYTiles;
  1026. posXFact := FWidth / FXTiles;
  1027. posYFact := FHeight / FYTiles;
  1028. if FMesh = nil then
  1029. begin
  1030. SetLength(FMesh, FYTiles + 1, FXTiles + 1);
  1031. for Y := 0 to FYTiles do
  1032. begin
  1033. texT1 := Y * texTFact;
  1034. pY1 := Y * posYFact - hh;
  1035. for X := 0 to FXTiles do
  1036. begin
  1037. texS := X * texSFact;
  1038. pX := X * posXFact - hw;
  1039. FMesh[Y][X].Position := Vector3fMake(pX, pY1, 0.0);
  1040. FMesh[Y][X].TexCoord := Vector2fMake(texS, texT1);
  1041. end;
  1042. end;
  1043. end;
  1044. end;
  1045. gl.Begin_(GL_TRIANGLES);
  1046. for Y := 0 to FYTiles - 1 do
  1047. begin
  1048. for X := 0 to FXTiles - 1 do
  1049. begin
  1050. pVertex := @FMesh[Y][X];
  1051. EmitVertex(pVertex);
  1052. pVertex := @FMesh[Y][X + 1];
  1053. EmitVertex(pVertex);
  1054. pVertex := @FMesh[Y + 1][X];
  1055. EmitVertex(pVertex);
  1056. pVertex := @FMesh[Y + 1][X + 1];
  1057. EmitVertex(pVertex);
  1058. pVertex := @FMesh[Y + 1][X];
  1059. EmitVertex(pVertex);
  1060. pVertex := @FMesh[Y][X + 1];
  1061. EmitVertex(pVertex);
  1062. end;
  1063. end;
  1064. gl.End_;
  1065. end;
  1066. procedure TGLPlane.SetWidth(const aValue: Single);
  1067. begin
  1068. if aValue <> FWidth then
  1069. begin
  1070. FWidth := aValue;
  1071. FMesh := nil;
  1072. StructureChanged;
  1073. end;
  1074. end;
  1075. function TGLPlane.ScreenRect(aBuffer: TGLSceneBuffer): TRect;
  1076. var
  1077. v: array [0 .. 3] of TGLVector;
  1078. buf: TGLSceneBuffer;
  1079. hw, hh: TGLFloat;
  1080. begin
  1081. buf := aBuffer;
  1082. if Assigned(buf) then
  1083. begin
  1084. hw := FWidth * 0.5;
  1085. hh := FHeight * 0.5;
  1086. v[0] := LocalToAbsolute(PointMake(-hw, -hh, 0));
  1087. v[1] := LocalToAbsolute(PointMake(hw, -hh, 0));
  1088. v[2] := LocalToAbsolute(PointMake(hw, hh, 0));
  1089. v[3] := LocalToAbsolute(PointMake(-hw, hh, 0));
  1090. buf.WorldToScreen(@v[0], 4);
  1091. Result.Left := Round(MinFloat([v[0].X, v[1].X, v[2].X, v[3].X]));
  1092. Result.Right := Round(MaxFloat([v[0].X, v[1].X, v[2].X, v[3].X]));
  1093. Result.Top := Round(MinFloat([v[0].Y, v[1].Y, v[2].Y, v[3].Y]));
  1094. Result.Bottom := Round(MaxFloat([v[0].Y, v[1].Y, v[2].Y, v[3].Y]));
  1095. end
  1096. else
  1097. FillChar(Result, SizeOf(TRect), 0);
  1098. end;
  1099. function TGLPlane.PointDistance(const aPoint: TGLVector): Single;
  1100. begin
  1101. Result := VectorDotProduct(VectorSubtract(aPoint, AbsolutePosition),
  1102. AbsoluteDirection);
  1103. end;
  1104. procedure TGLPlane.SetHeight(const aValue: Single);
  1105. begin
  1106. if aValue <> FHeight then
  1107. begin
  1108. FHeight := aValue;
  1109. FMesh := nil;
  1110. StructureChanged;
  1111. end;
  1112. end;
  1113. procedure TGLPlane.SetXOffset(const Value: TGLFloat);
  1114. begin
  1115. if Value <> FXOffset then
  1116. begin
  1117. FXOffset := Value;
  1118. FMesh := nil;
  1119. StructureChanged;
  1120. end;
  1121. end;
  1122. procedure TGLPlane.SetXScope(const Value: TGLFloat);
  1123. begin
  1124. if Value <> FXScope then
  1125. begin
  1126. FXScope := Value;
  1127. if FXScope > 1 then
  1128. FXScope := 1;
  1129. FMesh := nil;
  1130. StructureChanged;
  1131. end;
  1132. end;
  1133. function TGLPlane.StoreXScope: Boolean;
  1134. begin
  1135. Result := (FXScope <> 1);
  1136. end;
  1137. procedure TGLPlane.SetXTiles(const Value: Cardinal);
  1138. begin
  1139. if Value <> FXTiles then
  1140. begin
  1141. FXTiles := Value;
  1142. FMesh := nil;
  1143. StructureChanged;
  1144. end;
  1145. end;
  1146. procedure TGLPlane.SetYOffset(const Value: TGLFloat);
  1147. begin
  1148. if Value <> FYOffset then
  1149. begin
  1150. FYOffset := Value;
  1151. FMesh := nil;
  1152. StructureChanged;
  1153. end;
  1154. end;
  1155. procedure TGLPlane.SetYScope(const Value: TGLFloat);
  1156. begin
  1157. if Value <> FYScope then
  1158. begin
  1159. FYScope := Value;
  1160. if FYScope > 1 then
  1161. FYScope := 1;
  1162. FMesh := nil;
  1163. StructureChanged;
  1164. end;
  1165. end;
  1166. function TGLPlane.StoreYScope: Boolean;
  1167. begin
  1168. Result := (FYScope <> 1);
  1169. end;
  1170. procedure TGLPlane.SetYTiles(const Value: Cardinal);
  1171. begin
  1172. if Value <> FYTiles then
  1173. begin
  1174. FYTiles := Value;
  1175. FMesh := nil;
  1176. StructureChanged;
  1177. end;
  1178. end;
  1179. procedure TGLPlane.SetStyle(const val: TGLPlaneStyles);
  1180. begin
  1181. if val <> FStyle then
  1182. begin
  1183. FStyle := val;
  1184. StructureChanged;
  1185. end;
  1186. end;
  1187. // ------------------
  1188. // ------------------ TGLSprite ------------------
  1189. // ------------------
  1190. constructor TGLSprite.Create(AOwner: TComponent);
  1191. begin
  1192. inherited Create(AOwner);
  1193. ObjectStyle := ObjectStyle + [osDirectDraw, osNoVisibilityCulling];
  1194. FAlphaChannel := 1;
  1195. FWidth := 1;
  1196. FHeight := 1;
  1197. end;
  1198. procedure TGLSprite.Assign(Source: TPersistent);
  1199. begin
  1200. if Source is TGLSprite then
  1201. begin
  1202. FWidth := TGLSprite(Source).FWidth;
  1203. FHeight := TGLSprite(Source).FHeight;
  1204. FRotation := TGLSprite(Source).FRotation;
  1205. FAlphaChannel := TGLSprite(Source).FAlphaChannel;
  1206. end;
  1207. inherited Assign(Source);
  1208. end;
  1209. function TGLSprite.AxisAlignedDimensionsUnscaled: TGLVector;
  1210. begin
  1211. Result.X := 0.5 * Abs(FWidth);
  1212. Result.Y := 0.5 * Abs(FHeight);
  1213. // Sprites turn with the camera and can be considered to have the same depth
  1214. // as width
  1215. Result.Z := 0.5 * Abs(FWidth);
  1216. end;
  1217. procedure TGLSprite.BuildList(var rci: TGLRenderContextInfo);
  1218. var
  1219. vx, vy: TAffineVector;
  1220. W, h: Single;
  1221. mat: TGLMatrix;
  1222. u0, v0, u1, v1: Integer;
  1223. begin
  1224. if FAlphaChannel <> 1 then
  1225. rci.GLStates.SetGLMaterialAlphaChannel(GL_FRONT, FAlphaChannel);
  1226. mat := rci.PipelineTransformation.ModelViewMatrix^;
  1227. // extraction of the direction vectors of the matrix
  1228. W := FWidth * 0.5;
  1229. h := FHeight * 0.5;
  1230. vx.X := mat.v[0].X;
  1231. vy.X := mat.v[0].Y;
  1232. vx.Y := mat.v[1].X;
  1233. vy.Y := mat.v[1].Y;
  1234. vx.Z := mat.v[2].X;
  1235. vy.Z := mat.v[2].Y;
  1236. ScaleVector(vx, W / VectorLength(vx));
  1237. ScaleVector(vy, h / VectorLength(vy));
  1238. if FMirrorU then
  1239. begin
  1240. u0 := 1;
  1241. u1 := 0;
  1242. end
  1243. else
  1244. begin
  1245. u0 := 0;
  1246. u1 := 1;
  1247. end;
  1248. if FMirrorV then
  1249. begin
  1250. v0 := 1;
  1251. v1 := 0;
  1252. end
  1253. else
  1254. begin
  1255. v0 := 0;
  1256. v1 := 1;
  1257. end;
  1258. if FRotation <> 0 then
  1259. begin
  1260. gl.PushMatrix;
  1261. gl.Rotatef(FRotation, mat.v[0].Z, mat.v[1].Z, mat.v[2].Z);
  1262. end;
  1263. gl.Begin_(GL_QUADS);
  1264. xgl.TexCoord2f(u1, v1);
  1265. gl.Vertex3f(vx.X + vy.X, vx.Y + vy.Y, vx.Z + vy.Z);
  1266. xgl.TexCoord2f(u0, v1);
  1267. gl.Vertex3f(-vx.X + vy.X, -vx.Y + vy.Y, -vx.Z + vy.Z);
  1268. xgl.TexCoord2f(u0, v0);
  1269. gl.Vertex3f(-vx.X - vy.X, -vx.Y - vy.Y, -vx.Z - vy.Z);
  1270. xgl.TexCoord2f(u1, v0);
  1271. gl.Vertex3f(vx.X - vy.X, vx.Y - vy.Y, vx.Z - vy.Z);
  1272. gl.End_;
  1273. if FRotation <> 0 then
  1274. gl.PopMatrix;
  1275. end;
  1276. procedure TGLSprite.SetWidth(const val: TGLFloat);
  1277. begin
  1278. if FWidth <> val then
  1279. begin
  1280. FWidth := val;
  1281. NotifyChange(Self);
  1282. end;
  1283. end;
  1284. procedure TGLSprite.SetHeight(const val: TGLFloat);
  1285. begin
  1286. if FHeight <> val then
  1287. begin
  1288. FHeight := val;
  1289. NotifyChange(Self);
  1290. end;
  1291. end;
  1292. procedure TGLSprite.SetRotation(const val: TGLFloat);
  1293. begin
  1294. if FRotation <> val then
  1295. begin
  1296. FRotation := val;
  1297. NotifyChange(Self);
  1298. end;
  1299. end;
  1300. procedure TGLSprite.SetAlphaChannel(const val: Single);
  1301. begin
  1302. if val <> FAlphaChannel then
  1303. begin
  1304. if val < 0 then
  1305. FAlphaChannel := 0
  1306. else if val > 1 then
  1307. FAlphaChannel := 1
  1308. else
  1309. FAlphaChannel := val;
  1310. NotifyChange(Self);
  1311. end;
  1312. end;
  1313. function TGLSprite.StoreAlphaChannel: Boolean;
  1314. begin
  1315. Result := (FAlphaChannel <> 1);
  1316. end;
  1317. procedure TGLSprite.SetMirrorU(const val: Boolean);
  1318. begin
  1319. FMirrorU := val;
  1320. NotifyChange(Self);
  1321. end;
  1322. procedure TGLSprite.SetMirrorV(const val: Boolean);
  1323. begin
  1324. FMirrorV := val;
  1325. NotifyChange(Self);
  1326. end;
  1327. procedure TGLSprite.SetSize(const Width, Height: TGLFloat);
  1328. begin
  1329. FWidth := Width;
  1330. FHeight := Height;
  1331. NotifyChange(Self);
  1332. end;
  1333. procedure TGLSprite.SetSquareSize(const Size: TGLFloat);
  1334. begin
  1335. FWidth := Size;
  1336. FHeight := Size;
  1337. NotifyChange(Self);
  1338. end;
  1339. // ------------------
  1340. // ------------------ TGLPointParameters ------------------
  1341. // ------------------
  1342. constructor TGLPointParameters.Create(AOwner: TPersistent);
  1343. begin
  1344. inherited Create(AOwner);
  1345. FMinSize := 0;
  1346. FMaxSize := 128;
  1347. FFadeTresholdSize := 1;
  1348. FDistanceAttenuation := TGLCoordinates.CreateInitialized(Self, XHmgVector,
  1349. csVector);
  1350. end;
  1351. destructor TGLPointParameters.Destroy;
  1352. begin
  1353. FDistanceAttenuation.Free;
  1354. inherited;
  1355. end;
  1356. procedure TGLPointParameters.Assign(Source: TPersistent);
  1357. begin
  1358. if Source is TGLPointParameters then
  1359. begin
  1360. FMinSize := TGLPointParameters(Source).FMinSize;
  1361. FMaxSize := TGLPointParameters(Source).FMaxSize;
  1362. FFadeTresholdSize := TGLPointParameters(Source).FFadeTresholdSize;
  1363. FDistanceAttenuation.Assign(TGLPointParameters(Source).DistanceAttenuation);
  1364. end;
  1365. end;
  1366. procedure TGLPointParameters.DefineProperties(Filer: TFiler);
  1367. var
  1368. defaultParams: Boolean;
  1369. begin
  1370. inherited;
  1371. defaultParams := (FMaxSize = 128) and (FMinSize = 0) and
  1372. (FFadeTresholdSize = 1);
  1373. Filer.DefineBinaryProperty('PointParams', ReadData, WriteData,
  1374. not defaultParams);
  1375. end;
  1376. procedure TGLPointParameters.ReadData(Stream: TStream);
  1377. begin
  1378. with Stream do
  1379. begin
  1380. Read(FMinSize, SizeOf(Single));
  1381. Read(FMaxSize, SizeOf(Single));
  1382. Read(FFadeTresholdSize, SizeOf(Single));
  1383. end;
  1384. end;
  1385. procedure TGLPointParameters.WriteData(Stream: TStream);
  1386. begin
  1387. with Stream do
  1388. begin
  1389. Write(FMinSize, SizeOf(Single));
  1390. Write(FMaxSize, SizeOf(Single));
  1391. Write(FFadeTresholdSize, SizeOf(Single));
  1392. end;
  1393. end;
  1394. procedure TGLPointParameters.Apply;
  1395. begin
  1396. if Enabled and GL.ARB_point_parameters then
  1397. begin
  1398. gl.PointParameterf(GL_POINT_SIZE_MIN_ARB, FMinSize);
  1399. gl.PointParameterf(GL_POINT_SIZE_MAX_ARB, FMaxSize);
  1400. gl.PointParameterf(GL_POINT_FADE_THRESHOLD_SIZE_ARB, FFadeTresholdSize);
  1401. gl.PointParameterfv(GL_DISTANCE_ATTENUATION_EXT,
  1402. FDistanceAttenuation.AsAddress);
  1403. end;
  1404. end;
  1405. procedure TGLPointParameters.UnApply;
  1406. begin
  1407. if Enabled and GL.ARB_point_parameters then
  1408. begin
  1409. gl.PointParameterf(GL_POINT_SIZE_MIN_ARB, 0);
  1410. gl.PointParameterf(GL_POINT_SIZE_MAX_ARB, 128);
  1411. gl.PointParameterf(GL_POINT_FADE_THRESHOLD_SIZE_ARB, 1);
  1412. gl.PointParameterfv(GL_DISTANCE_ATTENUATION_EXT, @XVector);
  1413. end;
  1414. end;
  1415. procedure TGLPointParameters.SetEnabled(const val: Boolean);
  1416. begin
  1417. if val <> FEnabled then
  1418. begin
  1419. FEnabled := val;
  1420. NotifyChange(Self);
  1421. end;
  1422. end;
  1423. procedure TGLPointParameters.SetMinSize(const val: Single);
  1424. begin
  1425. if val <> FMinSize then
  1426. begin
  1427. if val < 0 then
  1428. FMinSize := 0
  1429. else
  1430. FMinSize := val;
  1431. NotifyChange(Self);
  1432. end;
  1433. end;
  1434. procedure TGLPointParameters.SetMaxSize(const val: Single);
  1435. begin
  1436. if val <> FMaxSize then
  1437. begin
  1438. if val < 0 then
  1439. FMaxSize := 0
  1440. else
  1441. FMaxSize := val;
  1442. NotifyChange(Self);
  1443. end;
  1444. end;
  1445. procedure TGLPointParameters.SetFadeTresholdSize(const val: Single);
  1446. begin
  1447. if val <> FFadeTresholdSize then
  1448. begin
  1449. if val < 0 then
  1450. FFadeTresholdSize := 0
  1451. else
  1452. FFadeTresholdSize := val;
  1453. NotifyChange(Self);
  1454. end;
  1455. end;
  1456. procedure TGLPointParameters.SetDistanceAttenuation(const val: TGLCoordinates);
  1457. begin
  1458. FDistanceAttenuation.Assign(val);
  1459. end;
  1460. // ------------------
  1461. // ------------------ TGLPoints ------------------
  1462. // ------------------
  1463. constructor TGLPoints.Create(AOwner: TComponent);
  1464. begin
  1465. inherited Create(AOwner);
  1466. ObjectStyle := ObjectStyle + [osDirectDraw, osNoVisibilityCulling];
  1467. FStyle := psSquare;
  1468. FSize := cDefaultPointSize;
  1469. FPositions := TGLAffineVectorList.Create;
  1470. FPositions.Add(NullVector);
  1471. FColors := TGLVectorList.Create;
  1472. FPointParameters := TGLPointParameters.Create(Self);
  1473. end;
  1474. destructor TGLPoints.Destroy;
  1475. begin
  1476. FPointParameters.Free;
  1477. FColors.Free;
  1478. FPositions.Free;
  1479. inherited;
  1480. end;
  1481. procedure TGLPoints.Assign(Source: TPersistent);
  1482. begin
  1483. if Source is TGLPoints then
  1484. begin
  1485. FSize := TGLPoints(Source).FSize;
  1486. FStyle := TGLPoints(Source).FStyle;
  1487. FPositions.Assign(TGLPoints(Source).FPositions);
  1488. FColors.Assign(TGLPoints(Source).FColors);
  1489. StructureChanged
  1490. end;
  1491. inherited Assign(Source);
  1492. end;
  1493. procedure TGLPoints.BuildList(var rci: TGLRenderContextInfo);
  1494. var
  1495. n: Integer;
  1496. v: TGLVector;
  1497. begin
  1498. n := FPositions.Count;
  1499. if n = 0 then
  1500. Exit;
  1501. case FColors.Count of
  1502. 0:
  1503. gl.Color4f(1, 1, 1, 1);
  1504. 1:
  1505. gl.Color4fv(PGLFloat(FColors.List));
  1506. else
  1507. if FColors.Count < n then
  1508. n := FColors.Count;
  1509. gl.ColorPointer(4, GL_FLOAT, 0, FColors.List);
  1510. gl.EnableClientState(GL_COLOR_ARRAY);
  1511. end;
  1512. if FColors.Count < 2 then
  1513. gl.DisableClientState(GL_COLOR_ARRAY);
  1514. rci.GLStates.Disable(stLighting);
  1515. if n = 0 then
  1516. begin
  1517. v := NullHmgPoint;
  1518. gl.VertexPointer(3, GL_FLOAT, 0, @v);
  1519. n := 1;
  1520. end
  1521. else
  1522. gl.VertexPointer(3, GL_FLOAT, 0, FPositions.List);
  1523. gl.EnableClientState(GL_VERTEX_ARRAY);
  1524. if NoZWrite then
  1525. rci.GLStates.DepthWriteMask := False;
  1526. rci.GLStates.PointSize := FSize;
  1527. PointParameters.Apply;
  1528. if GL.EXT_compiled_vertex_array and (n > 64) then
  1529. gl.LockArrays(0, n);
  1530. case FStyle of
  1531. psSquare:
  1532. begin
  1533. // square point (simplest method, fastest)
  1534. rci.GLStates.Disable(stBlend);
  1535. end;
  1536. psRound:
  1537. begin
  1538. rci.GLStates.Enable(stPointSmooth);
  1539. rci.GLStates.Enable(stAlphaTest);
  1540. rci.GLStates.SetGLAlphaFunction(cfGreater, 0.5);
  1541. rci.GLStates.Disable(stBlend);
  1542. end;
  1543. psSmooth:
  1544. begin
  1545. rci.GLStates.Enable(stPointSmooth);
  1546. rci.GLStates.Enable(stAlphaTest);
  1547. rci.GLStates.SetGLAlphaFunction(cfNotEqual, 0.0);
  1548. rci.GLStates.Enable(stBlend);
  1549. rci.GLStates.SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
  1550. end;
  1551. psSmoothAdditive:
  1552. begin
  1553. rci.GLStates.Enable(stPointSmooth);
  1554. rci.GLStates.Enable(stAlphaTest);
  1555. rci.GLStates.SetGLAlphaFunction(cfNotEqual, 0.0);
  1556. rci.GLStates.Enable(stBlend);
  1557. rci.GLStates.SetBlendFunc(bfSrcAlpha, bfOne);
  1558. end;
  1559. psSquareAdditive:
  1560. begin
  1561. rci.GLStates.Enable(stBlend);
  1562. rci.GLStates.SetBlendFunc(bfSrcAlpha, bfOne);
  1563. end;
  1564. else
  1565. Assert(False);
  1566. end;
  1567. gl.DrawArrays(GL_POINTS, 0, n);
  1568. if GL.EXT_compiled_vertex_array and (n > 64) then
  1569. gl.UnlockArrays;
  1570. PointParameters.UnApply;
  1571. gl.DisableClientState(GL_VERTEX_ARRAY);
  1572. if FColors.Count > 1 then
  1573. gl.DisableClientState(GL_COLOR_ARRAY);
  1574. end;
  1575. function TGLPoints.StoreSize: Boolean;
  1576. begin
  1577. Result := (FSize <> cDefaultPointSize);
  1578. end;
  1579. procedure TGLPoints.SetNoZWrite(const val: Boolean);
  1580. begin
  1581. if FNoZWrite <> val then
  1582. begin
  1583. FNoZWrite := val;
  1584. StructureChanged;
  1585. end;
  1586. end;
  1587. procedure TGLPoints.SetStatic(const val: Boolean);
  1588. begin
  1589. if FStatic <> val then
  1590. begin
  1591. FStatic := val;
  1592. if val then
  1593. ObjectStyle := ObjectStyle - [osDirectDraw]
  1594. else
  1595. ObjectStyle := ObjectStyle + [osDirectDraw];
  1596. StructureChanged;
  1597. end;
  1598. end;
  1599. procedure TGLPoints.SetSize(const val: Single);
  1600. begin
  1601. if FSize <> val then
  1602. begin
  1603. FSize := val;
  1604. StructureChanged;
  1605. end;
  1606. end;
  1607. procedure TGLPoints.SetPositions(const val: TGLAffineVectorList);
  1608. begin
  1609. FPositions.Assign(val);
  1610. StructureChanged;
  1611. end;
  1612. procedure TGLPoints.SetColors(const val: TGLVectorList);
  1613. begin
  1614. FColors.Assign(val);
  1615. StructureChanged;
  1616. end;
  1617. procedure TGLPoints.SetStyle(const val: TGLPointStyle);
  1618. begin
  1619. if FStyle <> val then
  1620. begin
  1621. FStyle := val;
  1622. StructureChanged;
  1623. end;
  1624. end;
  1625. procedure TGLPoints.SetPointParameters(const val: TGLPointParameters);
  1626. begin
  1627. FPointParameters.Assign(val);
  1628. end;
  1629. // ------------------
  1630. // ------------------ TGLLineBase ------------------
  1631. // ------------------
  1632. constructor TGLLineBase.Create(AOwner: TComponent);
  1633. begin
  1634. inherited Create(AOwner);
  1635. FLineColor := TGLColor.Create(Self);
  1636. FLineColor.Initialize(clrWhite);
  1637. FLinePattern := $FFFF;
  1638. FAntiAliased := False;
  1639. FLineWidth := 1.0;
  1640. end;
  1641. destructor TGLLineBase.Destroy;
  1642. begin
  1643. FLineColor.Free;
  1644. inherited Destroy;
  1645. end;
  1646. procedure TGLLineBase.NotifyChange(Sender: TObject);
  1647. begin
  1648. if Sender = FLineColor then
  1649. StructureChanged;
  1650. inherited;
  1651. end;
  1652. procedure TGLLineBase.SetLineColor(const Value: TGLColor);
  1653. begin
  1654. FLineColor.Color := Value.Color;
  1655. StructureChanged;
  1656. end;
  1657. procedure TGLLineBase.SetLinePattern(const Value: TGLushort);
  1658. begin
  1659. if FLinePattern <> Value then
  1660. begin
  1661. FLinePattern := Value;
  1662. StructureChanged;
  1663. end;
  1664. end;
  1665. procedure TGLLineBase.SetLineWidth(const val: Single);
  1666. begin
  1667. if FLineWidth <> val then
  1668. begin
  1669. FLineWidth := val;
  1670. StructureChanged;
  1671. end;
  1672. end;
  1673. function TGLLineBase.StoreLineWidth: Boolean;
  1674. begin
  1675. Result := (FLineWidth <> 1.0);
  1676. end;
  1677. procedure TGLLineBase.SetAntiAliased(const val: Boolean);
  1678. begin
  1679. if FAntiAliased <> val then
  1680. begin
  1681. FAntiAliased := val;
  1682. StructureChanged;
  1683. end;
  1684. end;
  1685. procedure TGLLineBase.Assign(Source: TPersistent);
  1686. begin
  1687. if Source is TGLLineBase then
  1688. begin
  1689. LineColor := TGLLineBase(Source).FLineColor;
  1690. LinePattern := TGLLineBase(Source).FLinePattern;
  1691. LineWidth := TGLLineBase(Source).FLineWidth;
  1692. AntiAliased := TGLLineBase(Source).FAntiAliased;
  1693. end;
  1694. inherited Assign(Source);
  1695. end;
  1696. procedure TGLLineBase.SetupLineStyle(var rci: TGLRenderContextInfo);
  1697. begin
  1698. with rci.GLStates do
  1699. begin
  1700. Disable(stLighting);
  1701. if FLinePattern <> $FFFF then
  1702. begin
  1703. Enable(stLineStipple);
  1704. Enable(stBlend);
  1705. SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
  1706. LineStippleFactor := 1;
  1707. LineStipplePattern := FLinePattern;
  1708. end
  1709. else
  1710. Disable(stLineStipple);
  1711. if FAntiAliased then
  1712. begin
  1713. Enable(stLineSmooth);
  1714. Enable(stBlend);
  1715. SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
  1716. end
  1717. else
  1718. Disable(stLineSmooth);
  1719. LineWidth := FLineWidth;
  1720. if FLineColor.Alpha <> 1 then
  1721. begin
  1722. if not FAntiAliased then
  1723. begin
  1724. Enable(stBlend);
  1725. SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
  1726. end;
  1727. gl.Color4fv(FLineColor.AsAddress);
  1728. end
  1729. else
  1730. gl.Color3fv(FLineColor.AsAddress);
  1731. end;
  1732. end;
  1733. // ------------------
  1734. // ------------------ TGLLinesNode ------------------
  1735. // ------------------
  1736. constructor TGLLinesNode.Create(Collection: TCollection);
  1737. begin
  1738. inherited Create(Collection);
  1739. FColor := TGLColor.Create(Self);
  1740. FColor.Initialize((TGLLinesNodes(Collection).GetOwner as TGLLines)
  1741. .NodeColor.Color);
  1742. FColor.OnNotifyChange := OnColorChange;
  1743. end;
  1744. destructor TGLLinesNode.Destroy;
  1745. begin
  1746. FColor.Free;
  1747. inherited Destroy;
  1748. end;
  1749. procedure TGLLinesNode.Assign(Source: TPersistent);
  1750. begin
  1751. if Source is TGLLinesNode then
  1752. FColor.Assign(TGLLinesNode(Source).FColor);
  1753. inherited;
  1754. end;
  1755. procedure TGLLinesNode.SetColor(const val: TGLColor);
  1756. begin
  1757. FColor.Assign(val);
  1758. end;
  1759. procedure TGLLinesNode.OnColorChange(Sender: TObject);
  1760. begin
  1761. (Collection as TGLNodes).NotifyChange;
  1762. end;
  1763. function TGLLinesNode.StoreColor: Boolean;
  1764. begin
  1765. Result := not VectorEquals((TGLLinesNodes(Collection).GetOwner as TGLLines)
  1766. .NodeColor.Color, FColor.Color);
  1767. end;
  1768. // ------------------
  1769. // ------------------ TGLLinesNodes ------------------
  1770. // ------------------
  1771. constructor TGLLinesNodes.Create(AOwner: TComponent);
  1772. begin
  1773. inherited Create(AOwner, TGLLinesNode);
  1774. end;
  1775. procedure TGLLinesNodes.NotifyChange;
  1776. begin
  1777. if (GetOwner <> nil) then
  1778. (GetOwner as TGLBaseSceneObject).StructureChanged;
  1779. end;
  1780. // ------------------
  1781. // ------------------ TGLNodedLines ------------------
  1782. // ------------------
  1783. constructor TGLNodedLines.Create(AOwner: TComponent);
  1784. begin
  1785. inherited Create(AOwner);
  1786. FNodes := TGLLinesNodes.Create(Self);
  1787. FNodeColor := TGLColor.Create(Self);
  1788. FNodeColor.Initialize(clrBlue);
  1789. FNodeColor.OnNotifyChange := OnNodeColorChanged;
  1790. FOldNodeColor := clrBlue;
  1791. FNodesAspect := lnaAxes;
  1792. FNodeSize := 1;
  1793. end;
  1794. destructor TGLNodedLines.Destroy;
  1795. begin
  1796. FNodes.Free;
  1797. FNodeColor.Free;
  1798. inherited Destroy;
  1799. end;
  1800. procedure TGLNodedLines.SetNodesAspect(const Value: TGLLineNodesAspect);
  1801. begin
  1802. if Value <> FNodesAspect then
  1803. begin
  1804. FNodesAspect := Value;
  1805. StructureChanged;
  1806. end;
  1807. end;
  1808. procedure TGLNodedLines.SetNodeColor(const Value: TGLColor);
  1809. begin
  1810. FNodeColor.Color := Value.Color;
  1811. StructureChanged;
  1812. end;
  1813. procedure TGLNodedLines.OnNodeColorChanged(Sender: TObject);
  1814. var
  1815. i: Integer;
  1816. begin
  1817. // update color for nodes...
  1818. for i := 0 to Nodes.Count - 1 do
  1819. if VectorEquals(TGLLinesNode(Nodes[i]).Color.Color, FOldNodeColor) then
  1820. TGLLinesNode(Nodes[i]).Color.Assign(FNodeColor);
  1821. SetVector(FOldNodeColor, FNodeColor.Color);
  1822. end;
  1823. procedure TGLNodedLines.SetNodes(const aNodes: TGLLinesNodes);
  1824. begin
  1825. FNodes.Free;
  1826. FNodes := aNodes;
  1827. StructureChanged;
  1828. end;
  1829. procedure TGLNodedLines.SetNodeSize(const val: Single);
  1830. begin
  1831. if val <= 0 then
  1832. FNodeSize := 1
  1833. else
  1834. FNodeSize := val;
  1835. StructureChanged;
  1836. end;
  1837. function TGLNodedLines.StoreNodeSize: Boolean;
  1838. begin
  1839. Result := FNodeSize <> 1;
  1840. end;
  1841. procedure TGLNodedLines.Assign(Source: TPersistent);
  1842. begin
  1843. if Source is TGLNodedLines then
  1844. begin
  1845. SetNodes(TGLNodedLines(Source).FNodes);
  1846. FNodesAspect := TGLNodedLines(Source).FNodesAspect;
  1847. FNodeColor.Color := TGLNodedLines(Source).FNodeColor.Color;
  1848. FNodeSize := TGLNodedLines(Source).FNodeSize;
  1849. end;
  1850. inherited Assign(Source);
  1851. end;
  1852. procedure TGLNodedLines.DrawNode(var rci: TGLRenderContextInfo; X, Y, Z: Single;
  1853. Color: TGLColor);
  1854. begin
  1855. gl.PushMatrix;
  1856. gl.Translatef(X, Y, Z);
  1857. case NodesAspect of
  1858. lnaAxes:
  1859. AxesBuildList(rci, $CCCC, FNodeSize * 0.5);
  1860. lnaCube:
  1861. CubeWireframeBuildList(rci, FNodeSize, False, Color.Color);
  1862. else
  1863. Assert(False)
  1864. end;
  1865. gl.PopMatrix;
  1866. end;
  1867. function TGLNodedLines.AxisAlignedDimensionsUnscaled: TGLVector;
  1868. var
  1869. i: Integer;
  1870. begin
  1871. RstVector(Result);
  1872. for i := 0 to Nodes.Count - 1 do
  1873. MaxVector(Result, VectorAbs(Nodes[i].AsVector));
  1874. // EG: commented out, line below looks suspicious, since scale isn't taken
  1875. // into account in previous loop, must have been hiding another bug... somewhere...
  1876. // DivideVector(Result, Scale.AsVector); //DanB ?
  1877. end;
  1878. procedure TGLNodedLines.AddNode(const coords: TGLCoordinates);
  1879. var
  1880. n: TGLNode;
  1881. begin
  1882. n := Nodes.Add;
  1883. if Assigned(coords) then
  1884. n.AsVector := coords.AsVector;
  1885. StructureChanged;
  1886. end;
  1887. procedure TGLNodedLines.AddNode(const X, Y, Z: TGLFloat);
  1888. var
  1889. n: TGLNode;
  1890. begin
  1891. n := Nodes.Add;
  1892. n.AsVector := VectorMake(X, Y, Z, 1);
  1893. StructureChanged;
  1894. end;
  1895. procedure TGLNodedLines.AddNode(const Value: TGLVector);
  1896. var
  1897. n: TGLNode;
  1898. begin
  1899. n := Nodes.Add;
  1900. n.AsVector := Value;
  1901. StructureChanged;
  1902. end;
  1903. procedure TGLNodedLines.AddNode(const Value: TAffineVector);
  1904. var
  1905. n: TGLNode;
  1906. begin
  1907. n := Nodes.Add;
  1908. n.AsVector := VectorMake(Value);
  1909. StructureChanged;
  1910. end;
  1911. // ------------------
  1912. // ------------------ TGLLines ------------------
  1913. // ------------------
  1914. constructor TGLLines.Create(AOwner: TComponent);
  1915. begin
  1916. inherited Create(AOwner);
  1917. FDivision := 10;
  1918. FSplineMode := lsmLines;
  1919. FNURBSKnots := TGLSingleList.Create;
  1920. FNURBSOrder := 0;
  1921. FNURBSTolerance := 50;
  1922. end;
  1923. destructor TGLLines.Destroy;
  1924. begin
  1925. FNURBSKnots.Free;
  1926. inherited Destroy;
  1927. end;
  1928. procedure TGLLines.SetDivision(const Value: Integer);
  1929. begin
  1930. if Value <> FDivision then
  1931. begin
  1932. if Value < 1 then
  1933. FDivision := 1
  1934. else
  1935. FDivision := Value;
  1936. StructureChanged;
  1937. end;
  1938. end;
  1939. procedure TGLLines.SetOptions(const val: TGLLinesOptions);
  1940. begin
  1941. FOptions := val;
  1942. StructureChanged;
  1943. end;
  1944. procedure TGLLines.SetSplineMode(const val: TGLLineSplineMode);
  1945. begin
  1946. if FSplineMode <> val then
  1947. begin
  1948. FSplineMode := val;
  1949. StructureChanged;
  1950. end;
  1951. end;
  1952. procedure TGLLines.SetNURBSOrder(const val: Integer);
  1953. begin
  1954. if val <> FNURBSOrder then
  1955. begin
  1956. FNURBSOrder := val;
  1957. StructureChanged;
  1958. end;
  1959. end;
  1960. procedure TGLLines.SetNURBSTolerance(const val: Single);
  1961. begin
  1962. if val <> FNURBSTolerance then
  1963. begin
  1964. FNURBSTolerance := val;
  1965. StructureChanged;
  1966. end;
  1967. end;
  1968. procedure TGLLines.Assign(Source: TPersistent);
  1969. begin
  1970. if Source is TGLLines then
  1971. begin
  1972. FDivision := TGLLines(Source).FDivision;
  1973. FSplineMode := TGLLines(Source).FSplineMode;
  1974. FOptions := TGLLines(Source).FOptions;
  1975. end;
  1976. inherited Assign(Source);
  1977. end;
  1978. procedure TGLLines.BuildList(var rci: TGLRenderContextInfo);
  1979. var
  1980. i, n: Integer;
  1981. A, B, C: TGLFloat;
  1982. f: Single;
  1983. Spline: TCubicSpline;
  1984. vertexColor: TGLVector;
  1985. nodeBuffer: array of TAffineVector;
  1986. colorBuffer: array of TGLVector;
  1987. nurbsRenderer: PGLUNurbs;
  1988. begin
  1989. if Nodes.Count > 1 then
  1990. begin
  1991. // first, we setup the line color & stippling styles
  1992. SetupLineStyle(rci);
  1993. if rci.bufferDepthTest then
  1994. rci.GLStates.Enable(stDepthTest);
  1995. if loColorLogicXor in Options then
  1996. begin
  1997. rci.GLStates.Enable(stColorLogicOp);
  1998. rci.GLStates.LogicOpMode := loXOr;
  1999. end;
  2000. // Set up the control point buffer for Bezier splines and NURBS curves.
  2001. // If required this could be optimized by storing a cached node buffer.
  2002. if (FSplineMode = lsmBezierSpline) or (FSplineMode = lsmNURBSCurve) then
  2003. begin
  2004. SetLength(nodeBuffer, Nodes.Count);
  2005. SetLength(colorBuffer, Nodes.Count);
  2006. for i := 0 to Nodes.Count - 1 do
  2007. with TGLLinesNode(Nodes[i]) do
  2008. begin
  2009. nodeBuffer[i] := AsAffineVector;
  2010. colorBuffer[i] := Color.Color;
  2011. end;
  2012. end;
  2013. if FSplineMode = lsmBezierSpline then
  2014. begin
  2015. // map evaluator
  2016. rci.GLStates.PushAttrib([sttEval]);
  2017. gl.Enable(GL_MAP1_VERTEX_3);
  2018. gl.Enable(GL_MAP1_COLOR_4);
  2019. gl.Map1f(GL_MAP1_VERTEX_3, 0, 1, 3, Nodes.Count, @nodeBuffer[0]);
  2020. gl.Map1f(GL_MAP1_COLOR_4, 0, 1, 4, Nodes.Count, @colorBuffer[0]);
  2021. end;
  2022. // start drawing the line
  2023. if (FSplineMode = lsmNURBSCurve) and (FDivision >= 2) then
  2024. begin
  2025. if (FNURBSOrder > 0) and (FNURBSKnots.Count > 0) then
  2026. begin
  2027. nurbsRenderer := gluNewNurbsRenderer;
  2028. // try
  2029. gluNurbsProperty(nurbsRenderer, GLU_SAMPLING_TOLERANCE,
  2030. FNURBSTolerance);
  2031. gluNurbsProperty(nurbsRenderer, GLU_DISPLAY_MODE, GLU_FILL);
  2032. gluBeginCurve(nurbsRenderer);
  2033. gluNurbsCurve(nurbsRenderer, FNURBSKnots.Count, @FNURBSKnots.List[0], 3,
  2034. @nodeBuffer[0], FNURBSOrder, GL_MAP1_VERTEX_3);
  2035. gluEndCurve(nurbsRenderer);
  2036. // finally
  2037. gluDeleteNurbsRenderer(nurbsRenderer);
  2038. // end;
  2039. end;
  2040. end
  2041. else
  2042. begin
  2043. // lines, cubic splines or bezier
  2044. if FSplineMode = lsmSegments then
  2045. gl.Begin_(GL_LINES)
  2046. else if FSplineMode = lsmLoop then
  2047. gl.Begin_(GL_LINE_LOOP)
  2048. else
  2049. gl.Begin_(GL_LINE_STRIP);
  2050. if (FDivision < 2) or (FSplineMode in [lsmLines, lsmSegments, lsmLoop])
  2051. then
  2052. begin
  2053. // standard line(s), draw directly
  2054. if loUseNodeColorForLines in Options then
  2055. begin
  2056. // node color interpolation
  2057. for i := 0 to Nodes.Count - 1 do
  2058. with TGLLinesNode(Nodes[i]) do
  2059. begin
  2060. gl.Color4fv(Color.AsAddress);
  2061. gl.Vertex3f(X, Y, Z);
  2062. end;
  2063. end
  2064. else
  2065. begin
  2066. // single color
  2067. for i := 0 to Nodes.Count - 1 do
  2068. with Nodes[i] do
  2069. gl.Vertex3f(X, Y, Z);
  2070. end;
  2071. end
  2072. else if FSplineMode = lsmCubicSpline then
  2073. begin
  2074. // cubic spline
  2075. Spline := Nodes.CreateNewCubicSpline;
  2076. // try
  2077. f := 1 / FDivision;
  2078. for i := 0 to (Nodes.Count - 1) * FDivision do
  2079. begin
  2080. Spline.SplineXYZ(i * f, A, B, C);
  2081. if loUseNodeColorForLines in Options then
  2082. begin
  2083. n := (i div FDivision);
  2084. if n < Nodes.Count - 1 then
  2085. VectorLerp(TGLLinesNode(Nodes[n]).Color.Color,
  2086. TGLLinesNode(Nodes[n + 1]).Color.Color, (i mod FDivision) * f,
  2087. vertexColor)
  2088. else
  2089. SetVector(vertexColor, TGLLinesNode(Nodes[Nodes.Count - 1])
  2090. .Color.Color);
  2091. gl.Color4fv(@vertexColor);
  2092. end;
  2093. gl.Vertex3f(A, B, C);
  2094. end;
  2095. // finally
  2096. Spline.Free;
  2097. // end;
  2098. end
  2099. else if FSplineMode = lsmBezierSpline then
  2100. begin
  2101. f := 1 / FDivision;
  2102. for i := 0 to FDivision do
  2103. gl.EvalCoord1f(i * f);
  2104. end;
  2105. gl.End_;
  2106. end;
  2107. rci.GLStates.Disable(stColorLogicOp);
  2108. if FSplineMode = lsmBezierSpline then
  2109. rci.GLStates.PopAttrib;
  2110. if Length(nodeBuffer) > 0 then
  2111. begin
  2112. SetLength(nodeBuffer, 0);
  2113. SetLength(colorBuffer, 0);
  2114. end;
  2115. if FNodesAspect <> lnaInvisible then
  2116. begin
  2117. if not rci.ignoreBlendingRequests then
  2118. begin
  2119. rci.GLStates.Enable(stBlend);
  2120. rci.GLStates.SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
  2121. end;
  2122. for i := 0 to Nodes.Count - 1 do
  2123. with TGLLinesNode(Nodes[i]) do
  2124. DrawNode(rci, X, Y, Z, Color);
  2125. end;
  2126. end;
  2127. end;
  2128. // ------------------
  2129. // ------------------ TGLCube ------------------
  2130. // ------------------
  2131. constructor TGLCube.Create(AOwner: TComponent);
  2132. begin
  2133. inherited Create(AOwner);
  2134. FCubeSize := XYZVector;
  2135. FParts := [cpTop, cpBottom, cpFront, cpBack, cpLeft, cpRight];
  2136. FNormalDirection := ndOutside;
  2137. ObjectStyle := ObjectStyle + [osDirectDraw];
  2138. end;
  2139. procedure TGLCube.BuildList(var rci: TGLRenderContextInfo);
  2140. var
  2141. v1: TAffineVector;
  2142. v2: TAffineVector;
  2143. v1d: TAffineVector;
  2144. v2d: TAffineVector;
  2145. nd: TGLFloat;
  2146. TanLoc, BinLoc: Integer;
  2147. begin
  2148. VectorScale(FCubeSize, 0.5, v2);
  2149. v1 := VectorNegate(v2);
  2150. if FNormalDirection = ndInside then
  2151. begin
  2152. v1d := v2;
  2153. v2d := v1;
  2154. nd := -1
  2155. end
  2156. else
  2157. begin
  2158. v1d := v1;
  2159. v2d := v2;
  2160. nd := 1;
  2161. end;
  2162. if GL.ARB_shader_objects and (rci.GLStates.CurrentProgram > 0) then
  2163. begin
  2164. TanLoc := gl.GetAttribLocation(rci.GLStates.CurrentProgram,
  2165. TangentAttributeName);
  2166. BinLoc := gl.GetAttribLocation(rci.GLStates.CurrentProgram,
  2167. BinormalAttributeName);
  2168. end
  2169. else
  2170. begin
  2171. TanLoc := -1;
  2172. BinLoc := -1;
  2173. end;
  2174. gl.Begin_(GL_QUADS);
  2175. if cpFront in FParts then
  2176. begin
  2177. gl.Normal3f(0, 0, nd);
  2178. if TanLoc > -1 then
  2179. gl.VertexAttrib3f(TanLoc, nd, 0, 0);
  2180. if BinLoc > -1 then
  2181. gl.VertexAttrib3f(BinLoc, 0, nd, 0);
  2182. xgl.TexCoord2fv(@XYTexPoint);
  2183. gl.Vertex3fv(@v2);
  2184. xgl.TexCoord2fv(@YTexPoint);
  2185. gl.Vertex3f(v1d.X, v2d.Y, v2.Z);
  2186. xgl.TexCoord2fv(@NullTexPoint);
  2187. gl.Vertex3f(v1.X, v1.Y, v2.Z);
  2188. xgl.TexCoord2fv(@XTexPoint);
  2189. gl.Vertex3f(v2d.X, v1d.Y, v2.Z);
  2190. end;
  2191. if cpBack in FParts then
  2192. begin
  2193. gl.Normal3f(0, 0, -nd);
  2194. if TanLoc > -1 then
  2195. gl.VertexAttrib3f(TanLoc, -nd, 0, 0);
  2196. if BinLoc > -1 then
  2197. gl.VertexAttrib3f(BinLoc, 0, nd, 0);
  2198. xgl.TexCoord2fv(@YTexPoint);
  2199. gl.Vertex3f(v2.X, v2.Y, v1.Z);
  2200. xgl.TexCoord2fv(@NullTexPoint);
  2201. gl.Vertex3f(v2d.X, v1d.Y, v1.Z);
  2202. xgl.TexCoord2fv(@XTexPoint);
  2203. gl.Vertex3fv(@v1);
  2204. xgl.TexCoord2fv(@XYTexPoint);
  2205. gl.Vertex3f(v1d.X, v2d.Y, v1.Z);
  2206. end;
  2207. if cpLeft in FParts then
  2208. begin
  2209. gl.Normal3f(-nd, 0, 0);
  2210. if TanLoc > -1 then
  2211. gl.VertexAttrib3f(TanLoc, 0, 0, nd);
  2212. if BinLoc > -1 then
  2213. gl.VertexAttrib3f(BinLoc, 0, nd, 0);
  2214. xgl.TexCoord2fv(@XYTexPoint);
  2215. gl.Vertex3f(v1.X, v2.Y, v2.Z);
  2216. xgl.TexCoord2fv(@YTexPoint);
  2217. gl.Vertex3f(v1.X, v2d.Y, v1d.Z);
  2218. xgl.TexCoord2fv(@NullTexPoint);
  2219. gl.Vertex3fv(@v1);
  2220. xgl.TexCoord2fv(@XTexPoint);
  2221. gl.Vertex3f(v1.X, v1d.Y, v2d.Z);
  2222. end;
  2223. if cpRight in FParts then
  2224. begin
  2225. gl.Normal3f(nd, 0, 0);
  2226. if TanLoc > -1 then
  2227. gl.VertexAttrib3f(TanLoc, 0, 0, -nd);
  2228. if BinLoc > -1 then
  2229. gl.VertexAttrib3f(BinLoc, 0, nd, 0);
  2230. xgl.TexCoord2fv(@YTexPoint);
  2231. gl.Vertex3fv(@v2);
  2232. xgl.TexCoord2fv(@NullTexPoint);
  2233. gl.Vertex3f(v2.X, v1d.Y, v2d.Z);
  2234. xgl.TexCoord2fv(@XTexPoint);
  2235. gl.Vertex3f(v2.X, v1.Y, v1.Z);
  2236. xgl.TexCoord2fv(@XYTexPoint);
  2237. gl.Vertex3f(v2.X, v2d.Y, v1d.Z);
  2238. end;
  2239. if cpTop in FParts then
  2240. begin
  2241. gl.Normal3f(0, nd, 0);
  2242. if TanLoc > -1 then
  2243. gl.VertexAttrib3f(TanLoc, nd, 0, 0);
  2244. if BinLoc > -1 then
  2245. gl.VertexAttrib3f(BinLoc, 0, 0, -nd);
  2246. xgl.TexCoord2fv(@YTexPoint);
  2247. gl.Vertex3f(v1.X, v2.Y, v1.Z);
  2248. xgl.TexCoord2fv(@NullTexPoint);
  2249. gl.Vertex3f(v1d.X, v2.Y, v2d.Z);
  2250. xgl.TexCoord2fv(@XTexPoint);
  2251. gl.Vertex3fv(@v2);
  2252. xgl.TexCoord2fv(@XYTexPoint);
  2253. gl.Vertex3f(v2d.X, v2.Y, v1d.Z);
  2254. end;
  2255. if cpBottom in FParts then
  2256. begin
  2257. gl.Normal3f(0, -nd, 0);
  2258. if TanLoc > -1 then
  2259. gl.VertexAttrib3f(TanLoc, -nd, 0, 0);
  2260. if BinLoc > -1 then
  2261. gl.VertexAttrib3f(BinLoc, 0, 0, nd);
  2262. xgl.TexCoord2fv(@NullTexPoint);
  2263. gl.Vertex3fv(@v1);
  2264. xgl.TexCoord2fv(@XTexPoint);
  2265. gl.Vertex3f(v2d.X, v1.Y, v1d.Z);
  2266. xgl.TexCoord2fv(@XYTexPoint);
  2267. gl.Vertex3f(v2.X, v1.Y, v2.Z);
  2268. xgl.TexCoord2fv(@YTexPoint);
  2269. gl.Vertex3f(v1d.X, v1.Y, v2d.Z);
  2270. end;
  2271. gl.End_;
  2272. end;
  2273. function TGLCube.GenerateSilhouette(const silhouetteParameters
  2274. : TGLSilhouetteParameters): TGLSilhouette;
  2275. var
  2276. hw, hh, hd: TGLFloat;
  2277. Connectivity: TGLConnectivity;
  2278. sil: TGLSilhouette;
  2279. begin
  2280. Connectivity := TGLConnectivity.Create(True);
  2281. hw := FCubeSize.X * 0.5;
  2282. hh := FCubeSize.Y * 0.5;
  2283. hd := FCubeSize.Z * 0.5;
  2284. if cpFront in FParts then
  2285. begin
  2286. Connectivity.AddQuad(AffineVectorMake(hw, hh, hd),
  2287. AffineVectorMake(-hw, hh, hd), AffineVectorMake(-hw, -hh, hd),
  2288. AffineVectorMake(hw, -hh, hd));
  2289. end;
  2290. if cpBack in FParts then
  2291. begin
  2292. Connectivity.AddQuad(AffineVectorMake(hw, hh, -hd),
  2293. AffineVectorMake(hw, -hh, -hd), AffineVectorMake(-hw, -hh, -hd),
  2294. AffineVectorMake(-hw, hh, -hd));
  2295. end;
  2296. if cpLeft in FParts then
  2297. begin
  2298. Connectivity.AddQuad(AffineVectorMake(-hw, hh, hd),
  2299. AffineVectorMake(-hw, hh, -hd), AffineVectorMake(-hw, -hh, -hd),
  2300. AffineVectorMake(-hw, -hh, hd));
  2301. end;
  2302. if cpRight in FParts then
  2303. begin
  2304. Connectivity.AddQuad(AffineVectorMake(hw, hh, hd),
  2305. AffineVectorMake(hw, -hh, hd), AffineVectorMake(hw, -hh, -hd),
  2306. AffineVectorMake(hw, hh, -hd));
  2307. end;
  2308. if cpTop in FParts then
  2309. begin
  2310. Connectivity.AddQuad(AffineVectorMake(-hw, hh, -hd),
  2311. AffineVectorMake(-hw, hh, hd), AffineVectorMake(hw, hh, hd),
  2312. AffineVectorMake(hw, hh, -hd));
  2313. end;
  2314. if cpBottom in FParts then
  2315. begin
  2316. Connectivity.AddQuad(AffineVectorMake(-hw, -hh, -hd),
  2317. AffineVectorMake(hw, -hh, -hd), AffineVectorMake(hw, -hh, hd),
  2318. AffineVectorMake(-hw, -hh, hd));
  2319. end;
  2320. sil := nil;
  2321. Connectivity.CreateSilhouette(silhouetteParameters, sil, False);
  2322. Result := sil;
  2323. Connectivity.Free;
  2324. end;
  2325. function TGLCube.GetCubeWHD(const Index: Integer): TGLFloat;
  2326. begin
  2327. Result := FCubeSize.v[index];
  2328. end;
  2329. procedure TGLCube.SetCubeWHD(Index: Integer; aValue: TGLFloat);
  2330. begin
  2331. if aValue <> FCubeSize.v[index] then
  2332. begin
  2333. FCubeSize.v[index] := aValue;
  2334. StructureChanged;
  2335. end;
  2336. end;
  2337. procedure TGLCube.SetParts(aValue: TGLCubeParts);
  2338. begin
  2339. if aValue <> FParts then
  2340. begin
  2341. FParts := aValue;
  2342. StructureChanged;
  2343. end;
  2344. end;
  2345. procedure TGLCube.SetNormalDirection(aValue: TGLNormalDirection);
  2346. begin
  2347. if aValue <> FNormalDirection then
  2348. begin
  2349. FNormalDirection := aValue;
  2350. StructureChanged;
  2351. end;
  2352. end;
  2353. procedure TGLCube.Assign(Source: TPersistent);
  2354. begin
  2355. if Assigned(Source) and (Source is TGLCube) then
  2356. begin
  2357. FCubeSize := TGLCube(Source).FCubeSize;
  2358. FParts := TGLCube(Source).FParts;
  2359. FNormalDirection := TGLCube(Source).FNormalDirection;
  2360. end;
  2361. inherited Assign(Source);
  2362. end;
  2363. function TGLCube.AxisAlignedDimensionsUnscaled: TGLVector;
  2364. begin
  2365. Result.X := FCubeSize.X * 0.5;
  2366. Result.Y := FCubeSize.Y * 0.5;
  2367. Result.Z := FCubeSize.Z * 0.5;
  2368. Result.W := 0;
  2369. end;
  2370. function TGLCube.RayCastIntersect(const rayStart, rayVector: TGLVector;
  2371. intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil): Boolean;
  2372. var
  2373. p: array [0 .. 5] of TGLVector;
  2374. rv: TGLVector;
  2375. rs, r: TGLVector;
  2376. i: Integer;
  2377. t: Single;
  2378. eSize: TAffineVector;
  2379. begin
  2380. rs := AbsoluteToLocal(rayStart);
  2381. SetVector(rv, VectorNormalize(AbsoluteToLocal(rayVector)));
  2382. eSize.X := FCubeSize.X * 0.5 + 0.0001;
  2383. eSize.Y := FCubeSize.Y * 0.5 + 0.0001;
  2384. eSize.Z := FCubeSize.Z * 0.5 + 0.0001;
  2385. p[0] := XHmgVector;
  2386. p[1] := YHmgVector;
  2387. p[2] := ZHmgVector;
  2388. SetVector(p[3], -1, 0, 0);
  2389. SetVector(p[4], 0, -1, 0);
  2390. SetVector(p[5], 0, 0, -1);
  2391. for i := 0 to 5 do
  2392. begin
  2393. if VectorDotProduct(p[i], rv) > 0 then
  2394. begin
  2395. t := -(p[i].X * rs.X + p[i].Y * rs.Y + p[i].Z * rs.Z + 0.5 * FCubeSize.v
  2396. [i mod 3]) / (p[i].X * rv.X + p[i].Y * rv.Y + p[i].Z * rv.Z);
  2397. MakePoint(r, rs.X + t * rv.X, rs.Y + t * rv.Y, rs.Z + t * rv.Z);
  2398. if (Abs(r.X) <= eSize.X) and (Abs(r.Y) <= eSize.Y) and
  2399. (Abs(r.Z) <= eSize.Z) and
  2400. (VectorDotProduct(VectorSubtract(r, rs), rv) > 0) then
  2401. begin
  2402. if Assigned(intersectPoint) then
  2403. MakePoint(intersectPoint^, LocalToAbsolute(r));
  2404. if Assigned(intersectNormal) then
  2405. MakeVector(intersectNormal^, LocalToAbsolute(VectorNegate(p[i])));
  2406. Result := True;
  2407. Exit;
  2408. end;
  2409. end;
  2410. end;
  2411. Result := False;
  2412. end;
  2413. procedure TGLCube.DefineProperties(Filer: TFiler);
  2414. begin
  2415. inherited;
  2416. Filer.DefineBinaryProperty('CubeSize', ReadData, WriteData,
  2417. (FCubeSize.X <> 1) or (FCubeSize.Y <> 1) or (FCubeSize.Z <> 1));
  2418. end;
  2419. procedure TGLCube.ReadData(Stream: TStream);
  2420. begin
  2421. with Stream do
  2422. begin
  2423. Read(FCubeSize, SizeOf(TAffineVector));
  2424. end;
  2425. end;
  2426. procedure TGLCube.WriteData(Stream: TStream);
  2427. begin
  2428. with Stream do
  2429. begin
  2430. Write(FCubeSize, SizeOf(TAffineVector));
  2431. end;
  2432. end;
  2433. // ------------------
  2434. // ------------------ TGLQuadricObject ------------------
  2435. // ------------------
  2436. constructor TGLQuadricObject.Create(AOwner: TComponent);
  2437. begin
  2438. inherited;
  2439. FNormals := nsSmooth;
  2440. FNormalDirection := ndOutside;
  2441. end;
  2442. procedure TGLQuadricObject.SetNormals(aValue: TGLNormalSmoothing);
  2443. begin
  2444. if aValue <> FNormals then
  2445. begin
  2446. FNormals := aValue;
  2447. StructureChanged;
  2448. end;
  2449. end;
  2450. procedure TGLQuadricObject.SetNormalDirection(aValue: TGLNormalDirection);
  2451. begin
  2452. if aValue <> FNormalDirection then
  2453. begin
  2454. FNormalDirection := aValue;
  2455. StructureChanged;
  2456. end;
  2457. end;
  2458. procedure TGLQuadricObject.SetupQuadricParams(quadric: PGLUquadricObj);
  2459. const
  2460. cNormalSmoothinToEnum: array [nsFlat .. nsNone] of Cardinal = (GLU_FLAT,
  2461. GLU_SMOOTH, GLU_NONE);
  2462. begin
  2463. gluQuadricDrawStyle(quadric, GLU_FILL);
  2464. gluQuadricNormals(quadric, cNormalSmoothinToEnum[FNormals]);
  2465. SetNormalQuadricOrientation(quadric);
  2466. gluQuadricTexture(quadric, True);
  2467. end;
  2468. procedure TGLQuadricObject.SetNormalQuadricOrientation(quadric: PGLUquadricObj);
  2469. const
  2470. cNormalDirectionToEnum: array [ndInside .. ndOutside] of Cardinal =
  2471. (GLU_INSIDE, GLU_OUTSIDE);
  2472. begin
  2473. gluQuadricOrientation(quadric, cNormalDirectionToEnum[FNormalDirection]);
  2474. end;
  2475. procedure TGLQuadricObject.SetInvertedQuadricOrientation
  2476. (quadric: PGLUquadricObj);
  2477. const
  2478. cNormalDirectionToEnum: array [ndInside .. ndOutside] of Cardinal =
  2479. (GLU_OUTSIDE, GLU_INSIDE);
  2480. begin
  2481. gluQuadricOrientation(quadric, cNormalDirectionToEnum[FNormalDirection]);
  2482. end;
  2483. procedure TGLQuadricObject.Assign(Source: TPersistent);
  2484. begin
  2485. if Assigned(Source) and (Source is TGLQuadricObject) then
  2486. begin
  2487. FNormals := TGLQuadricObject(Source).FNormals;
  2488. FNormalDirection := TGLQuadricObject(Source).FNormalDirection;
  2489. end;
  2490. inherited Assign(Source);
  2491. end;
  2492. // ------------------
  2493. // ------------------ TGLSphere ------------------
  2494. // ------------------
  2495. constructor TGLSphere.Create(AOwner: TComponent);
  2496. begin
  2497. inherited Create(AOwner);
  2498. FRadius := 0.5;
  2499. FSlices := 16;
  2500. FStacks := 16;
  2501. FTop := 90;
  2502. FBottom := -90;
  2503. FStart := 0;
  2504. FStop := 360;
  2505. end;
  2506. procedure TGLSphere.BuildList(var rci: TGLRenderContextInfo);
  2507. var
  2508. v1, v2, N1: TAffineVector;
  2509. AngTop, AngBottom, AngStart, AngStop, StepV, StepH: Double;
  2510. SinP, CosP, SinP2, CosP2, SinT, CosT, Phi, Phi2, Theta: Double;
  2511. uTexCoord, uTexFactor, vTexFactor, vTexCoord0, vTexCoord1: Single;
  2512. i, j: Integer;
  2513. DoReverse: Boolean;
  2514. begin
  2515. DoReverse := (FNormalDirection = ndInside);
  2516. rci.GLStates.PushAttrib([sttPolygon]);
  2517. if DoReverse then
  2518. rci.GLStates.InvertFrontFace;
  2519. // common settings
  2520. AngTop := DegToRad(1.0 * FTop);
  2521. AngBottom := DegToRad(1.0 * FBottom);
  2522. AngStart := DegToRad(1.0 * FStart);
  2523. AngStop := DegToRad(1.0 * FStop);
  2524. StepH := (AngStop - AngStart) / FSlices;
  2525. StepV := (AngTop - AngBottom) / FStacks;
  2526. gl.PushMatrix;
  2527. gl.Scalef(Radius, Radius, Radius);
  2528. // top cap
  2529. if (FTop < 90) and (FTopCap in [ctCenter, ctFlat]) then
  2530. begin
  2531. gl.Begin_(GL_TRIANGLE_FAN);
  2532. SinCosine(AngTop, SinP, CosP);
  2533. xgl.TexCoord2f(0.5, 0.5);
  2534. if DoReverse then
  2535. gl.Normal3f(0, -1, 0)
  2536. else
  2537. gl.Normal3f(0, 1, 0);
  2538. if FTopCap = ctCenter then
  2539. gl.Vertex3f(0, 0, 0)
  2540. else
  2541. begin
  2542. gl.Vertex3f(0, SinP, 0);
  2543. N1 := YVector;
  2544. if DoReverse then
  2545. N1.Y := -N1.Y;
  2546. end;
  2547. v1.Y := SinP;
  2548. Theta := AngStart;
  2549. for i := 0 to FSlices do
  2550. begin
  2551. SinCosine(Theta, SinT, CosT);
  2552. v1.X := CosP * SinT;
  2553. v1.Z := CosP * CosT;
  2554. if FTopCap = ctCenter then
  2555. begin
  2556. N1 := VectorPerpendicular(YVector, v1);
  2557. if DoReverse then
  2558. NegateVector(N1);
  2559. end;
  2560. xgl.TexCoord2f(SinT * 0.5 + 0.5, CosT * 0.5 + 0.5);
  2561. gl.Normal3fv(@N1);
  2562. gl.Vertex3fv(@v1);
  2563. Theta := Theta + StepH;
  2564. end;
  2565. gl.End_;
  2566. end;
  2567. // main body
  2568. Phi := AngTop;
  2569. Phi2 := Phi - StepV;
  2570. uTexFactor := 1 / FSlices;
  2571. vTexFactor := 1 / FStacks;
  2572. for j := 0 to FStacks - 1 do
  2573. begin
  2574. Theta := AngStart;
  2575. SinCos(Phi, SinP, CosP);
  2576. SinCos(Phi2, SinP2, CosP2);
  2577. v1.Y := SinP;
  2578. v2.Y := SinP2;
  2579. vTexCoord0 := 1 - j * vTexFactor;
  2580. vTexCoord1 := 1 - (j + 1) * vTexFactor;
  2581. gl.Begin_(GL_TRIANGLE_STRIP);
  2582. for i := 0 to FSlices do
  2583. begin
  2584. SinCos(Theta, SinT, CosT);
  2585. v1.X := CosP * SinT;
  2586. v2.X := CosP2 * SinT;
  2587. v1.Z := CosP * CosT;
  2588. v2.Z := CosP2 * CosT;
  2589. uTexCoord := i * uTexFactor;
  2590. xgl.TexCoord2f(uTexCoord, vTexCoord0);
  2591. if DoReverse then
  2592. begin
  2593. N1 := VectorNegate(v1);
  2594. gl.Normal3fv(@N1);
  2595. end
  2596. else
  2597. gl.Normal3fv(@v1);
  2598. gl.Vertex3fv(@v1);
  2599. xgl.TexCoord2f(uTexCoord, vTexCoord1);
  2600. if DoReverse then
  2601. begin
  2602. N1 := VectorNegate(v2);
  2603. gl.Normal3fv(@N1);
  2604. end
  2605. else
  2606. gl.Normal3fv(@v2);
  2607. gl.Vertex3fv(@v2);
  2608. Theta := Theta + StepH;
  2609. end;
  2610. gl.End_;
  2611. Phi := Phi2;
  2612. Phi2 := Phi2 - StepV;
  2613. end;
  2614. // bottom cap
  2615. if (FBottom > -90) and (FBottomCap in [ctCenter, ctFlat]) then
  2616. begin
  2617. gl.Begin_(GL_TRIANGLE_FAN);
  2618. SinCos(AngBottom, SinP, CosP);
  2619. xgl.TexCoord2f(0.5, 0.5);
  2620. if DoReverse then
  2621. gl.Normal3f(0, 1, 0)
  2622. else
  2623. gl.Normal3f(0, -1, 0);
  2624. if FBottomCap = ctCenter then
  2625. gl.Vertex3f(0, 0, 0)
  2626. else
  2627. begin
  2628. gl.Vertex3f(0, SinP, 0);
  2629. if DoReverse then
  2630. MakeVector(N1, 0, -1, 0)
  2631. else
  2632. begin
  2633. N1 := YVector;
  2634. NegateVector(N1);
  2635. end;
  2636. end;
  2637. v1.Y := SinP;
  2638. Theta := AngStop;
  2639. for i := 0 to FSlices do
  2640. begin
  2641. SinCos(Theta, SinT, CosT);
  2642. v1.X := CosP * SinT;
  2643. v1.Z := CosP * CosT;
  2644. if FBottomCap = ctCenter then
  2645. begin
  2646. N1 := VectorPerpendicular(AffineVectorMake(0, -1, 0), v1);
  2647. if DoReverse then
  2648. NegateVector(N1);
  2649. end;
  2650. xgl.TexCoord2f(SinT * 0.5 + 0.5, CosT * 0.5 + 0.5);
  2651. gl.Normal3fv(@N1);
  2652. gl.Vertex3fv(@v1);
  2653. Theta := Theta - StepH;
  2654. end;
  2655. gl.End_;
  2656. end;
  2657. if DoReverse then
  2658. rci.GLStates.InvertFrontFace;
  2659. gl.PopMatrix;
  2660. rci.GLStates.PopAttrib;
  2661. end;
  2662. function TGLSphere.RayCastIntersect(const rayStart, rayVector: TGLVector;
  2663. intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil): Boolean;
  2664. var
  2665. i1, i2: TGLVector;
  2666. localStart, localVector: TGLVector;
  2667. begin
  2668. // compute coefficients of quartic polynomial
  2669. SetVector(localStart, AbsoluteToLocal(rayStart));
  2670. SetVector(localVector, AbsoluteToLocal(rayVector));
  2671. NormalizeVector(localVector);
  2672. if RayCastSphereIntersect(localStart, localVector, NullHmgVector, Radius, i1,
  2673. i2) > 0 then
  2674. begin
  2675. Result := True;
  2676. if Assigned(intersectPoint) then
  2677. SetVector(intersectPoint^, LocalToAbsolute(i1));
  2678. if Assigned(intersectNormal) then
  2679. begin
  2680. i1.W := 0; // vector transform
  2681. SetVector(intersectNormal^, LocalToAbsolute(i1));
  2682. end;
  2683. end
  2684. else
  2685. Result := False;
  2686. end;
  2687. function TGLSphere.GenerateSilhouette(const silhouetteParameters
  2688. : TGLSilhouetteParameters): TGLSilhouette;
  2689. var
  2690. i, j: Integer;
  2691. s, C, angleFactor: Single;
  2692. sVec, tVec: TAffineVector;
  2693. Segments: Integer;
  2694. begin
  2695. Segments := MaxInteger(FStacks, FSlices);
  2696. // determine a local orthonormal matrix, viewer-oriented
  2697. sVec := VectorCrossProduct(silhouetteParameters.SeenFrom, XVector);
  2698. if VectorLength(sVec) < 1E-3 then
  2699. sVec := VectorCrossProduct(silhouetteParameters.SeenFrom, YVector);
  2700. tVec := VectorCrossProduct(silhouetteParameters.SeenFrom, sVec);
  2701. NormalizeVector(sVec);
  2702. NormalizeVector(tVec);
  2703. // generate the silhouette (outline and capping)
  2704. Result := TGLSilhouette.Create;
  2705. angleFactor := (2 * PI) / Segments;
  2706. for i := 0 to Segments - 1 do
  2707. begin
  2708. SinCosine(i * angleFactor, FRadius, s, C);
  2709. Result.vertices.AddPoint(VectorCombine(sVec, tVec, s, C));
  2710. j := (i + 1) mod Segments;
  2711. Result.Indices.Add(i, j);
  2712. if silhouetteParameters.CappingRequired then
  2713. Result.CapIndices.Add(Segments, i, j)
  2714. end;
  2715. if silhouetteParameters.CappingRequired then
  2716. Result.vertices.Add(NullHmgPoint);
  2717. end;
  2718. procedure TGLSphere.SetBottom(aValue: TGLAngleLimit180);
  2719. begin
  2720. if FBottom <> aValue then
  2721. begin
  2722. FBottom := aValue;
  2723. StructureChanged;
  2724. end;
  2725. end;
  2726. procedure TGLSphere.SetBottomCap(aValue: TGLCapType);
  2727. begin
  2728. if FBottomCap <> aValue then
  2729. begin
  2730. FBottomCap := aValue;
  2731. StructureChanged;
  2732. end;
  2733. end;
  2734. procedure TGLSphere.SetRadius(const aValue: TGLFloat);
  2735. begin
  2736. if aValue <> FRadius then
  2737. begin
  2738. FRadius := aValue;
  2739. StructureChanged;
  2740. end;
  2741. end;
  2742. procedure TGLSphere.SetSlices(aValue: TGLInt);
  2743. begin
  2744. if aValue <> FSlices then
  2745. begin
  2746. if aValue <= 0 then
  2747. FSlices := 1
  2748. else
  2749. FSlices := aValue;
  2750. StructureChanged;
  2751. end;
  2752. end;
  2753. procedure TGLSphere.SetStacks(aValue: TGLInt);
  2754. begin
  2755. if aValue <> FStacks then
  2756. begin
  2757. if aValue <= 0 then
  2758. FStacks := 1
  2759. else
  2760. FStacks := aValue;
  2761. StructureChanged;
  2762. end;
  2763. end;
  2764. procedure TGLSphere.SetStart(aValue: TGLAngleLimit360);
  2765. begin
  2766. if FStart <> aValue then
  2767. begin
  2768. Assert(aValue <= FStop);
  2769. FStart := aValue;
  2770. StructureChanged;
  2771. end;
  2772. end;
  2773. procedure TGLSphere.SetStop(aValue: TGLAngleLimit360);
  2774. begin
  2775. if FStop <> aValue then
  2776. begin
  2777. Assert(aValue >= FStart);
  2778. FStop := aValue;
  2779. StructureChanged;
  2780. end;
  2781. end;
  2782. procedure TGLSphere.SetTop(aValue: TGLAngleLimit180);
  2783. begin
  2784. if FTop <> aValue then
  2785. begin
  2786. FTop := aValue;
  2787. StructureChanged;
  2788. end;
  2789. end;
  2790. procedure TGLSphere.SetTopCap(aValue: TGLCapType);
  2791. begin
  2792. if FTopCap <> aValue then
  2793. begin
  2794. FTopCap := aValue;
  2795. StructureChanged;
  2796. end;
  2797. end;
  2798. procedure TGLSphere.Assign(Source: TPersistent);
  2799. begin
  2800. if Assigned(Source) and (Source is TGLSphere) then
  2801. begin
  2802. FRadius := TGLSphere(Source).FRadius;
  2803. FSlices := TGLSphere(Source).FSlices;
  2804. FStacks := TGLSphere(Source).FStacks;
  2805. FBottom := TGLSphere(Source).FBottom;
  2806. FTop := TGLSphere(Source).FTop;
  2807. FStart := TGLSphere(Source).FStart;
  2808. FStop := TGLSphere(Source).FStop;
  2809. end;
  2810. inherited Assign(Source);
  2811. end;
  2812. function TGLSphere.AxisAlignedDimensionsUnscaled: TGLVector;
  2813. begin
  2814. Result.X := Abs(FRadius);
  2815. Result.Y := Result.X;
  2816. Result.Z := Result.X;
  2817. Result.W := 0;
  2818. end;
  2819. // ------------------
  2820. // ------------------ TGLPolygonBase ------------------
  2821. // ------------------
  2822. constructor TGLPolygonBase.Create(AOwner: TComponent);
  2823. begin
  2824. inherited Create(AOwner);
  2825. CreateNodes;
  2826. FDivision := 10;
  2827. FSplineMode := lsmLines;
  2828. end;
  2829. procedure TGLPolygonBase.CreateNodes;
  2830. begin
  2831. FNodes := TGLNodes.Create(Self);
  2832. end;
  2833. destructor TGLPolygonBase.Destroy;
  2834. begin
  2835. FNodes.Free;
  2836. inherited Destroy;
  2837. end;
  2838. procedure TGLPolygonBase.Assign(Source: TPersistent);
  2839. begin
  2840. if Source is TGLPolygonBase then
  2841. begin
  2842. SetNodes(TGLPolygonBase(Source).FNodes);
  2843. FDivision := TGLPolygonBase(Source).FDivision;
  2844. FSplineMode := TGLPolygonBase(Source).FSplineMode;
  2845. end;
  2846. inherited Assign(Source);
  2847. end;
  2848. procedure TGLPolygonBase.NotifyChange(Sender: TObject);
  2849. begin
  2850. if Sender = Nodes then
  2851. StructureChanged;
  2852. inherited;
  2853. end;
  2854. procedure TGLPolygonBase.SetDivision(const Value: Integer);
  2855. begin
  2856. if Value <> FDivision then
  2857. begin
  2858. if Value < 1 then
  2859. FDivision := 1
  2860. else
  2861. FDivision := Value;
  2862. StructureChanged;
  2863. end;
  2864. end;
  2865. procedure TGLPolygonBase.SetNodes(const aNodes: TGLNodes);
  2866. begin
  2867. FNodes.Assign(aNodes);
  2868. StructureChanged;
  2869. end;
  2870. procedure TGLPolygonBase.SetSplineMode(const val: TGLLineSplineMode);
  2871. begin
  2872. if FSplineMode <> val then
  2873. begin
  2874. FSplineMode := val;
  2875. StructureChanged;
  2876. end;
  2877. end;
  2878. procedure TGLPolygonBase.AddNode(const coords: TGLCoordinates);
  2879. var
  2880. n: TGLNode;
  2881. begin
  2882. n := Nodes.Add;
  2883. if Assigned(coords) then
  2884. n.AsVector := coords.AsVector;
  2885. StructureChanged;
  2886. end;
  2887. procedure TGLPolygonBase.AddNode(const X, Y, Z: TGLFloat);
  2888. var
  2889. n: TGLNode;
  2890. begin
  2891. n := Nodes.Add;
  2892. n.AsVector := VectorMake(X, Y, Z, 1);
  2893. StructureChanged;
  2894. end;
  2895. procedure TGLPolygonBase.AddNode(const Value: TGLVector);
  2896. var
  2897. n: TGLNode;
  2898. begin
  2899. n := Nodes.Add;
  2900. n.AsVector := Value;
  2901. StructureChanged;
  2902. end;
  2903. procedure TGLPolygonBase.AddNode(const Value: TAffineVector);
  2904. var
  2905. n: TGLNode;
  2906. begin
  2907. n := Nodes.Add;
  2908. n.AsVector := VectorMake(Value);
  2909. StructureChanged;
  2910. end;
  2911. // ------------------
  2912. // ------------------ TGLSuperellipsoid ------------------
  2913. // ------------------
  2914. constructor TGLSuperellipsoid.Create(AOwner: TComponent);
  2915. begin
  2916. inherited Create(AOwner);
  2917. FRadius := 0.5;
  2918. FVCurve := 1.0;
  2919. FHCurve := 1.0;
  2920. FSlices := 16;
  2921. FStacks := 16;
  2922. FTop := 90;
  2923. FBottom := -90;
  2924. FStart := 0;
  2925. FStop := 360;
  2926. end;
  2927. procedure TGLSuperellipsoid.BuildList(var rci: TGLRenderContextInfo);
  2928. var
  2929. CosPc1, SinPc1, CosTc2, SinTc2: Double;
  2930. tc1, tc2: Integer;
  2931. v1, v2, vs, N1: TAffineVector;
  2932. AngTop, AngBottom, AngStart, AngStop, StepV, StepH: Double;
  2933. SinP, CosP, SinP2, CosP2, SinT, CosT, Phi, Phi2, Theta: Double;
  2934. uTexCoord, uTexFactor, vTexFactor, vTexCoord0, vTexCoord1: Double;
  2935. i, j: Integer;
  2936. DoReverse: Boolean;
  2937. begin
  2938. DoReverse := (FNormalDirection = ndInside);
  2939. if DoReverse then
  2940. rci.GLStates.InvertFrontFace;
  2941. // common settings
  2942. AngTop := DegToRad(1.0 * FTop);
  2943. AngBottom := DegToRad(1.0 * FBottom);
  2944. AngStart := DegToRad(1.0 * FStart);
  2945. AngStop := DegToRad(1.0 * FStop);
  2946. StepH := (AngStop - AngStart) / FSlices;
  2947. StepV := (AngTop - AngBottom) / FStacks;
  2948. // Even integer used with the Power function, only produce positive points
  2949. tc1 := trunc(VCurve);
  2950. tc2 := trunc(HCurve);
  2951. if tc1 mod 2 = 0 then
  2952. VCurve := VCurve + 1E-6;
  2953. if tc2 mod 2 = 0 then
  2954. HCurve := HCurve - 1E-6;
  2955. // top cap
  2956. if (FTop < 90) and (FTopCap in [ctCenter, ctFlat]) then
  2957. begin
  2958. gl.Begin_(GL_TRIANGLE_FAN);
  2959. SinCos(AngTop, SinP, CosP);
  2960. xgl.TexCoord2f(0.5, 0.5);
  2961. if DoReverse then
  2962. gl.Normal3f(0, -1, 0)
  2963. else
  2964. gl.Normal3f(0, 1, 0);
  2965. if FTopCap = ctCenter then
  2966. gl.Vertex3f(0, 0, 0)
  2967. else
  2968. begin // FTopCap = ctFlat
  2969. if (Sign(SinP) = 1) or (tc1 = VCurve) then
  2970. SinPc1 := Power(SinP, VCurve)
  2971. else
  2972. SinPc1 := -Power(-SinP, VCurve);
  2973. gl.Vertex3f(0, SinPc1 * Radius, 0);
  2974. N1 := YVector;
  2975. if DoReverse then
  2976. N1.Y := -N1.Y;
  2977. end; // FTopCap = ctFlat
  2978. // v1.Y := SinP;
  2979. if (Sign(SinP) = 1) or (tc1 = VCurve) then
  2980. SinPc1 := Power(SinP, VCurve)
  2981. else
  2982. SinPc1 := -Power(-SinP, VCurve);
  2983. v1.Y := SinPc1;
  2984. Theta := AngStart;
  2985. for i := 0 to FSlices do
  2986. begin
  2987. SinCos(Theta, SinT, CosT);
  2988. // v1.X := CosP * SinT;
  2989. if (Sign(CosP) = 1) or (tc1 = VCurve) then
  2990. CosPc1 := Power(CosP, VCurve)
  2991. else
  2992. CosPc1 := -Power(-CosP, VCurve);
  2993. if (Sign(SinT) = 1) or (tc2 = HCurve) then
  2994. SinTc2 := Power(SinT, HCurve)
  2995. else
  2996. SinTc2 := -Power(-SinT, HCurve);
  2997. v1.X := CosPc1 * SinTc2;
  2998. // v1.Z := CosP * CosT;
  2999. if (Sign(CosT) = 1) or (tc2 = HCurve) then
  3000. CosTc2 := Power(CosT, HCurve)
  3001. else
  3002. CosTc2 := -Power(-CosT, HCurve);
  3003. v1.Z := CosPc1 * CosTc2;
  3004. if FTopCap = ctCenter then
  3005. begin
  3006. N1 := VectorPerpendicular(YVector, v1);
  3007. if DoReverse then
  3008. NegateVector(N1);
  3009. end;
  3010. // xgl.TexCoord2f(SinT * 0.5 + 0.5, CosT * 0.5 + 0.5);
  3011. xgl.TexCoord2f(SinTc2 * 0.5 + 0.5, CosTc2 * 0.5 + 0.5);
  3012. gl.Normal3fv(@N1);
  3013. vs := v1;
  3014. ScaleVector(vs, Radius);
  3015. gl.Vertex3fv(@vs);
  3016. Theta := Theta + StepH;
  3017. end;
  3018. gl.End_;
  3019. end;
  3020. // main body
  3021. Phi := AngTop;
  3022. Phi2 := Phi - StepV;
  3023. uTexFactor := 1 / FSlices;
  3024. vTexFactor := 1 / FStacks;
  3025. for j := 0 to FStacks - 1 do
  3026. begin
  3027. Theta := AngStart;
  3028. SinCos(Phi, SinP, CosP);
  3029. SinCos(Phi2, SinP2, CosP2);
  3030. if (Sign(SinP) = 1) or (tc1 = VCurve) then
  3031. SinPc1 := Power(SinP, VCurve)
  3032. else
  3033. SinPc1 := -Power(-SinP, VCurve);
  3034. v1.Y := SinPc1;
  3035. if (Sign(SinP2) = 1) or (tc1 = VCurve) then
  3036. SinPc1 := Power(SinP2, VCurve)
  3037. else
  3038. SinPc1 := -Power(-SinP2, VCurve);
  3039. v2.Y := SinPc1;
  3040. vTexCoord0 := 1 - j * vTexFactor;
  3041. vTexCoord1 := 1 - (j + 1) * vTexFactor;
  3042. gl.Begin_(GL_TRIANGLE_STRIP);
  3043. for i := 0 to FSlices do
  3044. begin
  3045. SinCos(Theta, SinT, CosT);
  3046. if (Sign(CosP) = 1) or (tc1 = VCurve) then
  3047. CosPc1 := Power(CosP, VCurve)
  3048. else
  3049. CosPc1 := -Power(-CosP, VCurve);
  3050. if (Sign(SinT) = 1) or (tc2 = HCurve) then
  3051. SinTc2 := Power(SinT, HCurve)
  3052. else
  3053. SinTc2 := -Power(-SinT, HCurve);
  3054. v1.X := CosPc1 * SinTc2;
  3055. if (Sign(CosP2) = 1) or (tc1 = VCurve) then
  3056. CosPc1 := Power(CosP2, VCurve)
  3057. else
  3058. CosPc1 := -Power(-CosP2, VCurve);
  3059. v2.X := CosPc1 * SinTc2;
  3060. if (Sign(CosP) = 1) or (tc1 = VCurve) then
  3061. CosPc1 := Power(CosP, VCurve)
  3062. else
  3063. CosPc1 := -Power(-CosP, VCurve);
  3064. if (Sign(CosT) = 1) or (tc2 = HCurve) then
  3065. CosTc2 := Power(CosT, HCurve)
  3066. else
  3067. CosTc2 := -Power(-CosT, HCurve);
  3068. v1.Z := CosPc1 * CosTc2;
  3069. if (Sign(CosP2) = 1) or (tc1 = VCurve) then
  3070. CosPc1 := Power(CosP2, VCurve)
  3071. else
  3072. CosPc1 := -Power(-CosP2, VCurve);
  3073. v2.Z := CosPc1 * CosTc2;
  3074. uTexCoord := i * uTexFactor;
  3075. xgl.TexCoord2f(uTexCoord, vTexCoord0);
  3076. if DoReverse then
  3077. begin
  3078. N1 := VectorNegate(v1);
  3079. gl.Normal3fv(@N1);
  3080. end
  3081. else
  3082. gl.Normal3fv(@v1);
  3083. vs := v1;
  3084. ScaleVector(vs, Radius);
  3085. gl.Vertex3fv(@vs);
  3086. xgl.TexCoord2f(uTexCoord, vTexCoord1);
  3087. if DoReverse then
  3088. begin
  3089. N1 := VectorNegate(v2);
  3090. gl.Normal3fv(@N1);
  3091. end
  3092. else
  3093. gl.Normal3fv(@v2);
  3094. vs := v2;
  3095. ScaleVector(vs, Radius);
  3096. gl.Vertex3fv(@vs);
  3097. Theta := Theta + StepH;
  3098. end;
  3099. gl.End_;
  3100. Phi := Phi2;
  3101. Phi2 := Phi2 - StepV;
  3102. end;
  3103. // bottom cap
  3104. if (FBottom > -90) and (FBottomCap in [ctCenter, ctFlat]) then
  3105. begin
  3106. gl.Begin_(GL_TRIANGLE_FAN);
  3107. SinCos(AngBottom, SinP, CosP);
  3108. xgl.TexCoord2f(0.5, 0.5);
  3109. if DoReverse then
  3110. gl.Normal3f(0, 1, 0)
  3111. else
  3112. gl.Normal3f(0, -1, 0);
  3113. if FBottomCap = ctCenter then
  3114. gl.Vertex3f(0, 0, 0)
  3115. else
  3116. begin // FTopCap = ctFlat
  3117. if (Sign(SinP) = 1) or (tc1 = VCurve) then
  3118. SinPc1 := Power(SinP, VCurve)
  3119. else
  3120. SinPc1 := -Power(-SinP, VCurve);
  3121. gl.Vertex3f(0, SinPc1 * Radius, 0);
  3122. if DoReverse then
  3123. MakeVector(N1, 0, -1, 0)
  3124. else
  3125. N1 := YVector;
  3126. end;
  3127. // v1.Y := SinP;
  3128. if (Sign(SinP) = 1) or (tc1 = VCurve) then
  3129. SinPc1 := Power(SinP, VCurve)
  3130. else
  3131. SinPc1 := -Power(-SinP, VCurve);
  3132. v1.Y := SinPc1;
  3133. Theta := AngStop;
  3134. for i := 0 to FSlices do
  3135. begin
  3136. SinCos(Theta, SinT, CosT);
  3137. // v1.X := CosP * SinT;
  3138. if (Sign(CosP) = 1) or (tc1 = VCurve) then
  3139. CosPc1 := Power(CosP, VCurve)
  3140. else
  3141. CosPc1 := -Power(-CosP, VCurve);
  3142. if (Sign(SinT) = 1) or (tc2 = HCurve) then
  3143. SinTc2 := Power(SinT, HCurve)
  3144. else
  3145. SinTc2 := -Power(-SinT, HCurve);
  3146. v1.X := CosPc1 * SinTc2;
  3147. // v1.Z := CosP * CosT;
  3148. if (Sign(CosT) = 1) or (tc2 = HCurve) then
  3149. CosTc2 := Power(CosT, HCurve)
  3150. else
  3151. CosTc2 := -Power(-CosT, HCurve);
  3152. v1.Z := CosPc1 * CosTc2;
  3153. if FBottomCap = ctCenter then
  3154. begin
  3155. N1 := VectorPerpendicular(AffineVectorMake(0, -1, 0), v1);
  3156. if DoReverse then
  3157. NegateVector(N1);
  3158. gl.Normal3fv(@N1);
  3159. end;
  3160. // xgl.TexCoord2f(SinT * 0.5 + 0.5, CosT * 0.5 + 0.5);
  3161. xgl.TexCoord2f(SinTc2 * 0.5 + 0.5, CosTc2 * 0.5 + 0.5);
  3162. vs := v1;
  3163. ScaleVector(vs, Radius);
  3164. gl.Vertex3fv(@vs);
  3165. Theta := Theta - StepH;
  3166. end;
  3167. gl.End_;
  3168. end;
  3169. if DoReverse then
  3170. rci.GLStates.InvertFrontFace;
  3171. end;
  3172. // This will probably not work
  3173. // RayCastSphereIntersect -> RayCastSuperellipsoidIntersect ?
  3174. function TGLSuperellipsoid.RayCastIntersect(const rayStart, rayVector: TGLVector;
  3175. intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil): Boolean;
  3176. var
  3177. i1, i2: TGLVector;
  3178. localStart, localVector: TGLVector;
  3179. begin
  3180. // compute coefficients of quartic polynomial
  3181. SetVector(localStart, AbsoluteToLocal(rayStart));
  3182. SetVector(localVector, AbsoluteToLocal(rayVector));
  3183. NormalizeVector(localVector);
  3184. if RayCastSphereIntersect(localStart, localVector, NullHmgVector, Radius, i1,
  3185. i2) > 0 then
  3186. begin
  3187. Result := True;
  3188. if Assigned(intersectPoint) then
  3189. SetVector(intersectPoint^, LocalToAbsolute(i1));
  3190. if Assigned(intersectNormal) then
  3191. begin
  3192. i1.W := 0; // vector transform
  3193. SetVector(intersectNormal^, LocalToAbsolute(i1));
  3194. end;
  3195. end
  3196. else
  3197. Result := False;
  3198. end;
  3199. // This will probably not work ?
  3200. function TGLSuperellipsoid.GenerateSilhouette(const silhouetteParameters
  3201. : TGLSilhouetteParameters): TGLSilhouette;
  3202. var
  3203. i, j: Integer;
  3204. s, C, angleFactor: Single;
  3205. sVec, tVec: TAffineVector;
  3206. Segments: Integer;
  3207. begin
  3208. Segments := MaxInteger(FStacks, FSlices);
  3209. // determine a local orthonormal matrix, viewer-oriented
  3210. sVec := VectorCrossProduct(silhouetteParameters.SeenFrom, XVector);
  3211. if VectorLength(sVec) < 1E-3 then
  3212. sVec := VectorCrossProduct(silhouetteParameters.SeenFrom, YVector);
  3213. tVec := VectorCrossProduct(silhouetteParameters.SeenFrom, sVec);
  3214. NormalizeVector(sVec);
  3215. NormalizeVector(tVec);
  3216. // generate the silhouette (outline and capping)
  3217. Result := TGLSilhouette.Create;
  3218. angleFactor := (2 * PI) / Segments;
  3219. for i := 0 to Segments - 1 do
  3220. begin
  3221. SinCosine(i * angleFactor, FRadius, s, C);
  3222. Result.vertices.AddPoint(VectorCombine(sVec, tVec, s, C));
  3223. j := (i + 1) mod Segments;
  3224. Result.Indices.Add(i, j);
  3225. if silhouetteParameters.CappingRequired then
  3226. Result.CapIndices.Add(Segments, i, j)
  3227. end;
  3228. if silhouetteParameters.CappingRequired then
  3229. Result.vertices.Add(NullHmgPoint);
  3230. end;
  3231. procedure TGLSuperellipsoid.SetBottom(aValue: TGLAngleLimit180);
  3232. begin
  3233. if FBottom <> aValue then
  3234. begin
  3235. FBottom := aValue;
  3236. StructureChanged;
  3237. end;
  3238. end;
  3239. procedure TGLSuperellipsoid.SetBottomCap(aValue: TGLCapType);
  3240. begin
  3241. if FBottomCap <> aValue then
  3242. begin
  3243. FBottomCap := aValue;
  3244. StructureChanged;
  3245. end;
  3246. end;
  3247. procedure TGLSuperellipsoid.SetHCurve(const aValue: TGLFloat);
  3248. begin
  3249. if aValue <> FHCurve then
  3250. begin
  3251. FHCurve := aValue;
  3252. StructureChanged;
  3253. end;
  3254. end;
  3255. procedure TGLSuperellipsoid.SetRadius(const aValue: TGLFloat);
  3256. begin
  3257. if aValue <> FRadius then
  3258. begin
  3259. FRadius := aValue;
  3260. StructureChanged;
  3261. end;
  3262. end;
  3263. procedure TGLSuperellipsoid.SetSlices(aValue: TGLInt);
  3264. begin
  3265. if aValue <> FSlices then
  3266. begin
  3267. if aValue <= 0 then
  3268. FSlices := 1
  3269. else
  3270. FSlices := aValue;
  3271. StructureChanged;
  3272. end;
  3273. end;
  3274. procedure TGLSuperellipsoid.SetStacks(aValue: TGLInt);
  3275. begin
  3276. if aValue <> FStacks then
  3277. begin
  3278. if aValue <= 0 then
  3279. FStacks := 1
  3280. else
  3281. FStacks := aValue;
  3282. StructureChanged;
  3283. end;
  3284. end;
  3285. procedure TGLSuperellipsoid.SetStart(aValue: TGLAngleLimit360);
  3286. begin
  3287. if FStart <> aValue then
  3288. begin
  3289. Assert(aValue <= FStop);
  3290. FStart := aValue;
  3291. StructureChanged;
  3292. end;
  3293. end;
  3294. procedure TGLSuperellipsoid.SetStop(aValue: TGLAngleLimit360);
  3295. begin
  3296. if FStop <> aValue then
  3297. begin
  3298. Assert(aValue >= FStart);
  3299. FStop := aValue;
  3300. StructureChanged;
  3301. end;
  3302. end;
  3303. procedure TGLSuperellipsoid.SetTop(aValue: TGLAngleLimit180);
  3304. begin
  3305. if FTop <> aValue then
  3306. begin
  3307. FTop := aValue;
  3308. StructureChanged;
  3309. end;
  3310. end;
  3311. procedure TGLSuperellipsoid.SetTopCap(aValue: TGLCapType);
  3312. begin
  3313. if FTopCap <> aValue then
  3314. begin
  3315. FTopCap := aValue;
  3316. StructureChanged;
  3317. end;
  3318. end;
  3319. procedure TGLSuperellipsoid.SetVCurve(const aValue: TGLFloat);
  3320. begin
  3321. if aValue <> FVCurve then
  3322. begin
  3323. FVCurve := aValue;
  3324. StructureChanged;
  3325. end;
  3326. end;
  3327. procedure TGLSuperellipsoid.Assign(Source: TPersistent);
  3328. begin
  3329. if Assigned(Source) and (Source is TGLSuperellipsoid) then
  3330. begin
  3331. FRadius := TGLSuperellipsoid(Source).FRadius;
  3332. FSlices := TGLSuperellipsoid(Source).FSlices;
  3333. FStacks := TGLSuperellipsoid(Source).FStacks;
  3334. FBottom := TGLSuperellipsoid(Source).FBottom;
  3335. FTop := TGLSuperellipsoid(Source).FTop;
  3336. FStart := TGLSuperellipsoid(Source).FStart;
  3337. FStop := TGLSuperellipsoid(Source).FStop;
  3338. end;
  3339. inherited Assign(Source);
  3340. end;
  3341. function TGLSuperellipsoid.AxisAlignedDimensionsUnscaled: TGLVector;
  3342. begin
  3343. Result.X := Abs(FRadius);
  3344. Result.Y := Result.X;
  3345. Result.Z := Result.X;
  3346. Result.W := 0;
  3347. end;
  3348. // -------------------------------------------------------------
  3349. initialization
  3350. // -------------------------------------------------------------
  3351. RegisterClasses([TGLSphere, TGLCube, TGLPlane, TGLSprite, TGLPoints,
  3352. TGLDummyCube, TGLLines, TGLSuperellipsoid]);
  3353. end.