2
0

GXS.Objects.pas 98 KB

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