2
0

GLS.Objects.pas 99 KB

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