| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642 |
- //
- // The graphics engine GLScene https://github.com/glscene
- //
- unit GLS.Objects;
- (*
- Implementation of basic scene objects plus some management routines.
- The registered classes are:
- [TGLSphere, TGLCube, TGLPlane, TGLSprite, TGLPoints,
- TGLDummyCube, TGLLines, TGLSuperellipsoid]
- All objects declared in this unit are part of the basic GLScene package,
- these are only simple objects and should be kept simple and lightweight.
- More complex or more specialized versions should be placed in dedicated
- units where they can grow and prosper untammed. "Generic" geometrical
- objects can be found in GLS.GeomObjects unit.
- *)
- interface
- {$I GLS.Scene.inc}
- uses
- Winapi.OpenGL,
- Winapi.OpenGLext,
- System.Types,
- System.Classes,
- System.SysUtils,
- System.Math,
- GLS.OpenGLTokens,
- GLS.OpenGLAdapter,
- GLS.VectorTypes,
- GLS.PipelineTransformation,
- GLS.VectorGeometry,
- GLS.Spline,
- GLS.VectorLists,
- GLS.Scene,
- GLS.Context,
- GLS.Silhouette,
- GLS.Color,
- GLS.RenderContextInfo,
- GLS.PersistentClasses,
- GLS.BaseClasses,
- GLS.Nodes,
- GLS.Coordinates,
- GLS.XOpenGL,
- GLS.State;
- const
- cDefaultPointSize: Single = 1.0;
- type
- TGLVisibilityDeterminationEvent = function(Sender: TObject;
- var rci: TGLRenderContextInfo): Boolean of object;
- PGLVertexRec = ^TGLVertexRec;
- TGLVertexRec = record
- Position: TVector3f;
- Normal: TVector3f;
- Binormal: TVector3f;
- Tangent: TVector3f;
- TexCoord: TVector2f;
- end;
- (* A simple cube, invisible at run-time.
- This is a usually non-visible object -except at design-time- used for
- building hierarchies or groups, when some kind of joint or movement
- mechanism needs be described, you can use DummyCubes.
- DummyCube's barycenter is its children's barycenter.
- The DummyCube can optionnally amalgamate all its children into a single
- display list (see Amalgamate property). *)
- TGLDummyCube = class(TGLCameraInvariantObject)
- private
- FCubeSize: TGLFloat;
- FEdgeColor: TGLColor;
- FVisibleAtRunTime, FAmalgamate: Boolean;
- FGroupList: TGLListHandle;
- FOnVisibilityDetermination: TGLVisibilityDeterminationEvent;
- protected
- procedure SetCubeSize(const val: TGLFloat); inline;
- procedure SetEdgeColor(const val: TGLColor); inline;
- procedure SetVisibleAtRunTime(const val: Boolean); inline;
- procedure SetAmalgamate(const val: Boolean); inline;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure Assign(Source: TPersistent); override;
- function AxisAlignedDimensionsUnscaled: TGLVector; override;
- function RayCastIntersect(const rayStart, rayVector: TGLVector;
- intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil)
- : Boolean; override;
- procedure BuildList(var rci: TGLRenderContextInfo); override;
- procedure DoRender(var rci: TGLRenderContextInfo;
- renderSelf, renderChildren: Boolean); override;
- procedure StructureChanged; override;
- function BarycenterAbsolutePosition: TGLVector; override;
- published
- property CubeSize: TGLFloat read FCubeSize write SetCubeSize;
- property EdgeColor: TGLColor read FEdgeColor write SetEdgeColor;
- (* If true the dummycube's edges will be visible at runtime.
- The default behaviour of the dummycube is to be visible at design-time
- only, and invisible at runtime. *)
- property VisibleAtRunTime: Boolean read FVisibleAtRunTime
- write SetVisibleAtRunTime default False;
- (* Amalgamate the dummy's children in a single OpenGL entity.
- This activates a special rendering mode, which will compile
- the rendering of all of the dummycube's children objects into a
- single display list. This may provide a significant speed up in some
- situations, however, this means that changes to the children will
- be ignored until you call StructureChanged on the dummy cube.
- Some objects, that have their own display list management, may not
- be compatible with this behaviour. This will also prevents sorting
- and culling to operate as usual.
- In short, this features is best used for static, non-transparent
- geometry, or when the point of view won't change over a large
- number of frames. *)
- property Amalgamate: Boolean read FAmalgamate write SetAmalgamate
- default False;
- (* Camera Invariance Options.
- These options allow to "deactivate" sensitivity to camera, f.i. by
- centering the object on the camera or ignoring camera orientation. *)
- property CamInvarianceMode default cimNone;
- (* Event for custom visibility determination.
- Event handler should return True if the dummycube and its children
- are to be considered visible for the current render. *)
- property OnVisibilityDetermination: TGLVisibilityDeterminationEvent
- read FOnVisibilityDetermination write FOnVisibilityDetermination;
- end;
- TGLPlaneStyle = (psSingleQuad, psTileTexture);
- TGLPlaneStyles = set of TGLPlaneStyle;
- (* A simple plane object.
- Note that a plane is always made of a single quad (two triangles) and the
- tiling is only applied to texture coordinates. *)
- TGLPlane = class(TGLSceneObject)
- private
- FXOffset, FYOffset: TGLFloat;
- FXScope, FYScope: TGLFloat;
- FWidth, FHeight: TGLFloat;
- FXTiles, FYTiles: Cardinal;
- FStyle: TGLPlaneStyles;
- FMesh: array of array of TGLVertexRec;
- protected
- procedure SetHeight(const aValue: Single);
- procedure SetWidth(const aValue: Single);
- procedure SetXOffset(const Value: TGLFloat);
- procedure SetXScope(const Value: TGLFloat);
- function StoreXScope: Boolean;
- procedure SetXTiles(const Value: Cardinal);
- procedure SetYOffset(const Value: TGLFloat);
- procedure SetYScope(const Value: TGLFloat);
- function StoreYScope: Boolean;
- procedure SetYTiles(const Value: Cardinal);
- procedure SetStyle(const val: TGLPlaneStyles);
- public
- constructor Create(AOwner: TComponent); override;
- procedure Assign(Source: TPersistent); override;
- procedure BuildList(var rci: TGLRenderContextInfo); override;
- function GenerateSilhouette(const silhouetteParameters
- : TGLSilhouetteParameters): TGLSilhouette; override;
- function AxisAlignedDimensionsUnscaled: TGLVector; override;
- function RayCastIntersect(const rayStart, rayVector: TGLVector;
- intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil)
- : Boolean; override;
- (* Computes the screen coordinates of the smallest rectangle encompassing the plane.
- Returned extents are NOT limited to any physical screen extents. *)
- function ScreenRect(aBuffer: TGLSceneBuffer): TRect;
- (* Computes the signed distance to the point.
- Point coordinates are expected in absolute coordinates. *)
- function PointDistance(const aPoint: TGLVector): Single;
- published
- property Height: TGLFloat read FHeight write SetHeight;
- property Width: TGLFloat read FWidth write SetWidth;
- property XOffset: TGLFloat read FXOffset write SetXOffset;
- property XScope: TGLFloat read FXScope write SetXScope stored StoreXScope;
- property XTiles: Cardinal read FXTiles write SetXTiles default 1;
- property YOffset: TGLFloat read FYOffset write SetYOffset;
- property YScope: TGLFloat read FYScope write SetYScope stored StoreYScope;
- property YTiles: Cardinal read FYTiles write SetYTiles default 1;
- property Style: TGLPlaneStyles read FStyle write SetStyle
- default [psSingleQuad, psTileTexture];
- end;
- (* A rectangular area, perspective projected, but always facing the camera.
- A TGLSprite is perspective projected and as such is scaled with distance,
- if you want a 2D sprite that does not get scaled, see TGLHUDSprite. *)
- TGLSprite = class(TGLSceneObject)
- private
- FWidth: TGLFloat;
- FHeight: TGLFloat;
- FRotation: TGLFloat;
- FAlphaChannel: Single;
- FMirrorU, FMirrorV: Boolean;
- protected
- procedure SetWidth(const val: TGLFloat);
- procedure SetHeight(const val: TGLFloat);
- procedure SetRotation(const val: TGLFloat);
- procedure SetAlphaChannel(const val: Single);
- function StoreAlphaChannel: Boolean;
- procedure SetMirrorU(const val: Boolean);
- procedure SetMirrorV(const val: Boolean);
- public
- constructor Create(AOwner: TComponent); override;
- procedure Assign(Source: TPersistent); override;
- procedure BuildList(var rci: TGLRenderContextInfo); override;
- function AxisAlignedDimensionsUnscaled: TGLVector; override;
- procedure SetSize(const Width, Height: TGLFloat);
- // Set width and height to "size"
- procedure SetSquareSize(const Size: TGLFloat);
- published
- // Sprite Width in 3D world units.
- property Width: TGLFloat read FWidth write SetWidth;
- // Sprite Height in 3D world units.
- property Height: TGLFloat read FHeight write SetHeight;
- (* This the ON-SCREEN rotation of the sprite.
- Rotatation=0 is handled faster. *)
- property Rotation: TGLFloat read FRotation write SetRotation;
- // If different from 1, this value will replace that of Diffuse.Alpha
- property AlphaChannel: Single read FAlphaChannel write SetAlphaChannel
- stored StoreAlphaChannel;
- // Reverses the texture coordinates in the U and V direction to mirror the texture.
- property MirrorU: Boolean read FMirrorU write SetMirrorU default False;
- property MirrorV: Boolean read FMirrorV write SetMirrorV default False;
- end;
- TGLPointStyle = (psSquare, psRound, psSmooth, psSmoothAdditive,
- psSquareAdditive);
- (* Point parameters as in ARB_point_parameters.
- Make sure to read the ARB_point_parameters spec if you want to understand
- what each parameter does. *)
- TGLPointParameters = class(TGLUpdateAbleObject)
- private
- FEnabled: Boolean;
- FMinSize, FMaxSize: Single;
- FFadeTresholdSize: Single;
- FDistanceAttenuation: TGLCoordinates;
- protected
- procedure SetEnabled(const val: Boolean);
- procedure SetMinSize(const val: Single);
- procedure SetMaxSize(const val: Single);
- procedure SetFadeTresholdSize(const val: Single);
- procedure SetDistanceAttenuation(const val: TGLCoordinates);
- procedure DefineProperties(Filer: TFiler); override;
- procedure ReadData(Stream: TStream);
- procedure WriteData(Stream: TStream);
- public
- constructor Create(AOwner: TPersistent); override;
- destructor Destroy; override;
- procedure Assign(Source: TPersistent); override;
- procedure Apply;
- procedure UnApply;
- published
- property Enabled: Boolean read FEnabled write SetEnabled default False;
- property MinSize: Single read FMinSize write SetMinSize stored False;
- property MaxSize: Single read FMaxSize write SetMaxSize stored False;
- property FadeTresholdSize: Single read FFadeTresholdSize
- write SetFadeTresholdSize stored False;
- // Components XYZ are for constant, linear and quadratic attenuation.
- property DistanceAttenuation: TGLCoordinates read FDistanceAttenuation
- write SetDistanceAttenuation;
- end;
- (* Renders a set of non-transparent colored points.
- The points positions and their color are defined through the Positions
- and Colors properties *)
- TGLPoints = class(TGLImmaterialSceneObject)
- private
- FPositions: TGLAffineVectorList;
- FColors: TGLVectorList;
- FSize: Single;
- FStyle: TGLPointStyle;
- FPointParameters: TGLPointParameters;
- FStatic, FNoZWrite: Boolean;
- protected
- function StoreSize: Boolean; inline;
- procedure SetNoZWrite(const val: Boolean);
- procedure SetStatic(const val: Boolean);
- procedure SetSize(const val: Single);
- procedure SetPositions(const val: TGLAffineVectorList); inline;
- procedure SetColors(const val: TGLVectorList);
- procedure SetStyle(const val: TGLPointStyle);
- procedure SetPointParameters(const val: TGLPointParameters);
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure Assign(Source: TPersistent); override;
- procedure BuildList(var rci: TGLRenderContextInfo); override;
- // Points positions. If empty, a single point is assumed at (0, 0, 0)
- property Positions: TGLAffineVectorList read FPositions write SetPositions;
- (* Defines the points colors:
- if empty, point color will be opaque white
- if contains a single color, all points will use that color
- if contains N colors, the first N points (at max) will be rendered
- using the corresponding colors *)
- property Colors: TGLVectorList read FColors write SetColors;
- published
- // If true points do not write their Z to the depth buffer.
- property NoZWrite: Boolean read FNoZWrite write SetNoZWrite;
- (* Tells the component if point coordinates are static.
- If static, changes to the positions should be notified via an
- explicit StructureChanged call, or may not refresh.
- Static sets of points may render faster than dynamic ones. *)
- property Static: Boolean read FStatic write SetStatic;
- // Point size, all points have a fixed size.
- property Size: Single read FSize write SetSize stored StoreSize;
- // Points style.
- property Style: TGLPointStyle read FStyle write SetStyle default psSquare;
- (* Point parameters as of ARB_point_parameters.
- Allows to vary the size and transparency of points depending
- on their distance to the observer. *)
- property PointParameters: TGLPointParameters read FPointParameters
- write SetPointParameters;
- end;
- // Possible aspects for the nodes of a TLine.
- TGLLineNodesAspect = (lnaInvisible, lnaAxes, lnaCube);
- // Available spline modes for a TLine.
- TGLLineSplineMode = (lsmLines, lsmCubicSpline, lsmBezierSpline, lsmNURBSCurve,
- lsmSegments, lsmLoop);
- // Specialized Node for use in a TGLLines objects. Adds a Color property (TGLColor) }
- TGLLinesNode = class(TGLNode)
- private
- FColor: TGLColor;
- protected
- procedure SetColor(const val: TGLColor);
- procedure OnColorChange(Sender: TObject);
- function StoreColor: Boolean;
- public
- constructor Create(Collection: TCollection); override;
- destructor Destroy; override;
- procedure Assign(Source: TPersistent); override;
- published
- (* The node color.
- Can also defined the line color (interpolated between nodes) if
- loUseNodeColorForLines is set (in TGLLines). *)
- property Color: TGLColor read FColor write SetColor stored StoreColor;
- end;
- (* Specialized collection for Nodes in a TGLLines objects. Stores TGLLinesNode items *)
- TGLLinesNodes = class(TGLNodes)
- public
- constructor Create(AOwner: TComponent); overload;
- procedure NotifyChange; override;
- end;
- (* Base class for line objects. Introduces line style properties (width, color...) *)
- TGLLineBase = class(TGLImmaterialSceneObject)
- private
- FLineColor: TGLColor;
- FLinePattern: TGLushort;
- FLineWidth: Single;
- FAntiAliased: Boolean;
- protected
- procedure SetLineColor(const Value: TGLColor);
- procedure SetLinePattern(const Value: TGLushort);
- procedure SetLineWidth(const val: Single);
- function StoreLineWidth: Boolean; inline;
- procedure SetAntiAliased(const val: Boolean);
- (* Setup OpenGL states according to line style.
- You must call RestoreLineStyle after drawing your lines.
- You may use nested calls with SetupLineStyle/RestoreLineStyle *)
- procedure SetupLineStyle(var rci: TGLRenderContextInfo);
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure Assign(Source: TPersistent); override;
- procedure NotifyChange(Sender: TObject); override;
- published
- (* Indicates if OpenGL should smooth line edges.
- Smoothed lines looks better but are poorly implemented in most OpenGL
- drivers and take *lots* of rendering time *)
- property AntiAliased: Boolean read FAntiAliased write SetAntiAliased
- default False;
- // Default color of the lines.
- property LineColor: TGLColor read FLineColor write SetLineColor;
- (* Bitwise line pattern.
- For instance $FFFF (65535) is a white line (stipple disabled), $0000
- is a black line, $CCCC is the stipple used in axes and dummycube, etc. *)
- property LinePattern: TGLushort read FLinePattern write SetLinePattern
- default $FFFF;
- // Default width of the lines.
- property LineWidth: Single read FLineWidth write SetLineWidth
- stored StoreLineWidth;
- property Visible;
- end;
- // Class that defines lines via a series of nodes. Base class, does not render anything
- TGLNodedLines = class(TGLLineBase)
- private
- FNodes: TGLLinesNodes;
- FNodesAspect: TGLLineNodesAspect;
- FNodeColor: TGLColor;
- FNodeSize: Single;
- FOldNodeColor: TGLColorVector;
- protected
- procedure SetNodesAspect(const Value: TGLLineNodesAspect);
- procedure SetNodeColor(const Value: TGLColor);
- procedure OnNodeColorChanged(Sender: TObject);
- procedure SetNodes(const aNodes: TGLLinesNodes);
- procedure SetNodeSize(const val: Single);
- function StoreNodeSize: Boolean;
- procedure DrawNode(var rci: TGLRenderContextInfo; X, Y, Z: Single;
- Color: TGLColor);
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure Assign(Source: TPersistent); override;
- function AxisAlignedDimensionsUnscaled: TGLVector; override;
- procedure AddNode(const coords: TGLCoordinates); overload;
- procedure AddNode(const X, Y, Z: TGLFloat); overload;
- procedure AddNode(const Value: TGLVector); overload;
- procedure AddNode(const Value: TAffineVector); overload;
- published
- // Default color for nodes. lnaInvisible and lnaAxes ignore this setting
- property NodeColor: TGLColor read FNodeColor write SetNodeColor;
- // The nodes list.
- property Nodes: TGLLinesNodes read FNodes write SetNodes;
- (* Default aspect of line nodes.
- May help you materialize nodes, segments and control points. *)
- property NodesAspect: TGLLineNodesAspect read FNodesAspect
- write SetNodesAspect default lnaAxes;
- // Size for the various node aspects.
- property NodeSize: Single read FNodeSize write SetNodeSize
- stored StoreNodeSize;
- end;
- TGLLinesOption = (loUseNodeColorForLines, loColorLogicXor);
- TGLLinesOptions = set of TGLLinesOption;
- (* Set of 3D line segments.
- You define a 3D Line by adding its nodes in the "Nodes" property. The line
- may be rendered as a set of segment or as a curve (nodes then act as spline
- control points).
- Alternatively, you can also use it to render a set of spacial nodes (points
- in space), just make the lines transparent and the nodes visible by picking
- the node aspect that suits you. *)
- TGLLines = class(TGLNodedLines)
- private
- FDivision: Integer;
- FSplineMode: TGLLineSplineMode;
- FOptions: TGLLinesOptions;
- FNURBSOrder: Integer;
- FNURBSTolerance: Single;
- FNURBSKnots: TGLSingleList;
- protected
- procedure SetSplineMode(const val: TGLLineSplineMode);
- procedure SetDivision(const Value: Integer);
- procedure SetOptions(const val: TGLLinesOptions);
- procedure SetNURBSOrder(const val: Integer);
- procedure SetNURBSTolerance(const val: Single);
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure Assign(Source: TPersistent); override;
- procedure BuildList(var rci: TGLRenderContextInfo); override;
- property NURBSKnots: TGLSingleList read FNURBSKnots;
- property NURBSOrder: Integer read FNURBSOrder write SetNURBSOrder;
- property NURBSTolerance: Single read FNURBSTolerance
- write SetNURBSTolerance;
- published
- (* Number of divisions for each segment in spline modes.
- Minimum 1 (disabled), ignored in lsmLines mode. *)
- property Division: Integer read FDivision write SetDivision default 10;
- // Default spline drawing mode.
- property SplineMode: TGLLineSplineMode read FSplineMode write SetSplineMode
- default lsmLines;
- (* Rendering options for the line.
- loUseNodeColorForLines: if set lines will be drawn using node
- colors (and color interpolation between nodes), if not, LineColor
- will be used (single color).
- loColorLogicXor: enable logic operation for color of XOR type. *)
- property Options: TGLLinesOptions read FOptions write SetOptions;
- end;
- TGLCubePart = (cpTop, cpBottom, cpFront, cpBack, cpLeft, cpRight);
- TGLCubeParts = set of TGLCubePart;
- (* A simple cube object.
- This cube use the same material for each of its faces, ie. all faces look
- the same. If you want a multi-material cube, use a mesh in conjunction
- with a TGLFreeForm and a material library.
- Ref: https://mathworld.wolfram.com/Cube.html *)
- TGLCube = class(TGLSceneObject)
- private
- FCubeSize: TAffineVector;
- FParts: TGLCubeParts;
- FNormalDirection: TGLNormalDirection;
- function GetCubeWHD(const Index: Integer): TGLFloat; inline;
- procedure SetCubeWHD(Index: Integer; aValue: TGLFloat); inline;
- procedure SetParts(aValue: TGLCubeParts); inline;
- procedure SetNormalDirection(aValue: TGLNormalDirection); inline;
- protected
- procedure DefineProperties(Filer: TFiler); override;
- procedure ReadData(Stream: TStream); inline;
- procedure WriteData(Stream: TStream); inline;
- public
- constructor Create(AOwner: TComponent); override;
- function GenerateSilhouette(const silhouetteParameters
- : TGLSilhouetteParameters): TGLSilhouette; override;
- procedure BuildList(var rci: TGLRenderContextInfo); override;
- procedure Assign(Source: TPersistent); override;
- function AxisAlignedDimensionsUnscaled: TGLVector; override;
- function RayCastIntersect(const rayStart, rayVector: TGLVector;
- intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil)
- : Boolean; override;
- published
- property CubeWidth: TGLFloat index 0 read GetCubeWHD write SetCubeWHD
- stored False;
- property CubeHeight: TGLFloat index 1 read GetCubeWHD write SetCubeWHD
- stored False;
- property CubeDepth: TGLFloat index 2 read GetCubeWHD write SetCubeWHD
- stored False;
- property NormalDirection: TGLNormalDirection read FNormalDirection
- write SetNormalDirection default ndOutside;
- property Parts: TGLCubeParts read FParts write SetParts
- default [cpTop, cpBottom, cpFront, cpBack, cpLeft, cpRight];
- end;
- (* Determines how and if normals are smoothed.
- - nsFlat : facetted look
- - nsSmooth : smooth look
- - nsNone : unlighted rendering, usefull for decla texturing *)
- TGLNormalSmoothing = (nsFlat, nsSmooth, nsNone);
- (* Base class for quadric objects.
- Introduces some basic Quadric interaction functions (the actual quadric
- math is part of the GLU library). *)
- TGLQuadricObject = class(TGLSceneObject)
- private
- FNormals: TGLNormalSmoothing;
- FNormalDirection: TGLNormalDirection;
- protected
- procedure SetNormals(aValue: TGLNormalSmoothing);
- procedure SetNormalDirection(aValue: TGLNormalDirection);
- procedure SetupQuadricParams(quadric: PGLUquadricObj);
- procedure SetNormalQuadricOrientation(quadric: PGLUquadricObj);
- procedure SetInvertedQuadricOrientation(quadric: PGLUquadricObj);
- public
- constructor Create(AOwner: TComponent); override;
- procedure Assign(Source: TPersistent); override;
- published
- property Normals: TGLNormalSmoothing read FNormals write SetNormals
- default nsSmooth;
- property NormalDirection: TGLNormalDirection read FNormalDirection
- write SetNormalDirection default ndOutside;
- end;
- TGLAngleLimit180 = -90 .. 90;
- TGLAngleLimit360 = 0 .. 360;
- TGLCapType = (ctNone, ctCenter, ctFlat);
- (* A sphere object.
- The sphere can have to and bottom caps, as well as being just a slice of sphere.
- Ref: https://mathworld.wolfram.com/Sphere.html
- Ref: https://mathworld.wolfram.com/GeodesicDome.html *)
- TGLSphere = class(TGLQuadricObject)
- private
- FRadius: TGLFloat;
- FSlices, FStacks: TGLInt;
- FTop: TGLAngleLimit180;
- FBottom: TGLAngleLimit180;
- FStart: TGLAngleLimit360;
- FStop: TGLAngleLimit360;
- FTopCap, FBottomCap: TGLCapType;
- procedure SetBottom(aValue: TGLAngleLimit180);
- procedure SetBottomCap(aValue: TGLCapType);
- procedure SetRadius(const aValue: TGLFloat);
- procedure SetSlices(aValue: TGLInt);
- procedure SetStart(aValue: TGLAngleLimit360);
- procedure SetStop(aValue: TGLAngleLimit360);
- procedure SetStacks(aValue: TGLInt);
- procedure SetTop(aValue: TGLAngleLimit180);
- procedure SetTopCap(aValue: TGLCapType);
- public
- constructor Create(AOwner: TComponent); override;
- procedure Assign(Source: TPersistent); override;
- procedure BuildList(var rci: TGLRenderContextInfo); override;
- function AxisAlignedDimensionsUnscaled: TGLVector; override;
- function RayCastIntersect(const rayStart, rayVector: TGLVector;
- intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil)
- : Boolean; override;
- function GenerateSilhouette(const silhouetteParameters
- : TGLSilhouetteParameters): TGLSilhouette; override;
- published
- property Bottom: TGLAngleLimit180 read FBottom write SetBottom default -90;
- property BottomCap: TGLCapType read FBottomCap write SetBottomCap
- default ctNone;
- property Radius: TGLFloat read FRadius write SetRadius;
- property Slices: TGLInt read FSlices write SetSlices default 16;
- property Stacks: TGLInt read FStacks write SetStacks default 16;
- property Start: TGLAngleLimit360 read FStart write SetStart default 0;
- property Stop: TGLAngleLimit360 read FStop write SetStop default 360;
- property Top: TGLAngleLimit180 read FTop write SetTop default 90;
- property TopCap: TGLCapType read FTopCap write SetTopCap default ctNone;
- end;
- (* Base class for objects based on a polygon *)
- TGLPolygonBase = class(TGLSceneObject)
- private
- FDivision: Integer;
- FSplineMode: TGLLineSplineMode;
- protected
- FNodes: TGLNodes;
- procedure CreateNodes; dynamic;
- procedure SetSplineMode(const val: TGLLineSplineMode);
- procedure SetDivision(const Value: Integer);
- procedure SetNodes(const aNodes: TGLNodes);
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure Assign(Source: TPersistent); override;
- procedure NotifyChange(Sender: TObject); override;
- procedure AddNode(const coords: TGLCoordinates); overload;
- procedure AddNode(const X, Y, Z: TGLFloat); overload;
- procedure AddNode(const Value: TGLVector); overload;
- procedure AddNode(const Value: TAffineVector); overload;
- published
- // The nodes list.
- property Nodes: TGLNodes read FNodes write SetNodes;
- (* Number of divisions for each segment in spline modes.
- Minimum 1 (disabled), ignored in lsmLines mode. *)
- property Division: Integer read FDivision write SetDivision default 10;
- (* Default spline drawing mode.
- This mode is used only for the curve, not for the rotation path. *)
- property SplineMode: TGLLineSplineMode read FSplineMode write SetSplineMode
- default lsmLines;
- end;
- (* A Superellipsoid object. The Superellipsoid can have top and bottom caps,
- as well as being just a slice of Superellipsoid.
- Ref: https://mathworld.wolfram.com/Superellipse.html *)
- TGLSuperellipsoid = class(TGLQuadricObject)
- private
- FRadius, FVCurve, FHCurve: TGLFloat;
- FSlices, FStacks: TGLInt;
- FTop: TGLAngleLimit180;
- FBottom: TGLAngleLimit180;
- FStart: TGLAngleLimit360;
- FStop: TGLAngleLimit360;
- FTopCap, FBottomCap: TGLCapType;
- procedure SetBottom(aValue: TGLAngleLimit180);
- procedure SetBottomCap(aValue: TGLCapType);
- procedure SetRadius(const aValue: TGLFloat);
- procedure SetVCurve(const aValue: TGLFloat);
- procedure SetHCurve(const aValue: TGLFloat);
- procedure SetSlices(aValue: TGLInt);
- procedure SetStart(aValue: TGLAngleLimit360);
- procedure SetStop(aValue: TGLAngleLimit360);
- procedure SetStacks(aValue: TGLInt);
- procedure SetTop(aValue: TGLAngleLimit180);
- procedure SetTopCap(aValue: TGLCapType);
- public
- constructor Create(AOwner: TComponent); override;
- procedure Assign(Source: TPersistent); override;
- procedure BuildList(var rci: TGLRenderContextInfo); override;
- function AxisAlignedDimensionsUnscaled: TGLVector; override;
- function RayCastIntersect(const rayStart, rayVector: TGLVector;
- intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil)
- : Boolean; override;
- function GenerateSilhouette(const silhouetteParameters
- : TGLSilhouetteParameters): TGLSilhouette; override;
- published
- property Bottom: TGLAngleLimit180 read FBottom write SetBottom default -90;
- property BottomCap: TGLCapType read FBottomCap write SetBottomCap
- default ctNone;
- property Radius: TGLFloat read FRadius write SetRadius;
- property VCurve: TGLFloat read FVCurve write SetVCurve;
- property HCurve: TGLFloat read FHCurve write SetHCurve;
- property Slices: TGLInt read FSlices write SetSlices default 16;
- property Stacks: TGLInt read FStacks write SetStacks default 16;
- property Start: TGLAngleLimit360 read FStart write SetStart default 0;
- property Stop: TGLAngleLimit360 read FStop write SetStop default 360;
- property Top: TGLAngleLimit180 read FTop write SetTop default 90;
- property TopCap: TGLCapType read FTopCap write SetTopCap default ctNone;
- end;
- // Issues for a unit-size cube stippled wireframe
- procedure CubeWireframeBuildList(var rci: TGLRenderContextInfo; Size: TGLFloat;
- Stipple: Boolean; const Color: TGLColorVector);
- const
- TangentAttributeName: PAnsiChar = 'Tangent';
- BinormalAttributeName: PAnsiChar = 'Binormal';
- // -------------------------------------------------------------
- implementation
- // -------------------------------------------------------------
- procedure CubeWireframeBuildList(var rci: TGLRenderContextInfo; Size: TGLFloat;
- Stipple: Boolean; const Color: TGLColorVector);
- var
- mi, ma: Single;
- begin
- {$IFDEF USE_OPENGL_DEBUG}
- if GL.GREMEDY_string_marker then
- gl.StringMarkerGREMEDY(22, 'CubeWireframeBuildList');
- {$ENDIF}
- rci.GLStates.Disable(stLighting);
- rci.GLStates.Enable(stLineSmooth);
- if Stipple then
- begin
- rci.GLStates.Enable(stLineStipple);
- rci.GLStates.Enable(stBlend);
- rci.GLStates.SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
- rci.GLStates.LineStippleFactor := 1;
- rci.GLStates.LineStipplePattern := $CCCC;
- end;
- rci.GLStates.LineWidth := 1;
- ma := 0.5 * Size;
- mi := -ma;
- gl.Color4fv(@Color);
- gl.Begin_(GL_LINE_STRIP);
- // front face
- gl.Vertex3f(ma, mi, mi);
- gl.Vertex3f(ma, ma, mi);
- gl.Vertex3f(ma, ma, ma);
- gl.Vertex3f(ma, mi, ma);
- gl.Vertex3f(ma, mi, mi);
- // partial up back face
- gl.Vertex3f(mi, mi, mi);
- gl.Vertex3f(mi, mi, ma);
- gl.Vertex3f(mi, ma, ma);
- gl.Vertex3f(mi, ma, mi);
- // right side low
- gl.Vertex3f(ma, ma, mi);
- gl.End_;
- gl.Begin_(GL_LINES);
- // right high
- gl.Vertex3f(ma, ma, ma);
- gl.Vertex3f(mi, ma, ma);
- // back low
- gl.Vertex3f(mi, mi, mi);
- gl.Vertex3f(mi, ma, mi);
- // left high
- gl.Vertex3f(ma, mi, ma);
- gl.Vertex3f(mi, mi, ma);
- gl.End_;
- end;
- // ------------------
- // ------------------ TGLDummyCube ------------------
- // ------------------
- constructor TGLDummyCube.Create(AOwner: TComponent);
- begin
- inherited;
- ObjectStyle := ObjectStyle + [osDirectDraw];
- FCubeSize := 1;
- FEdgeColor := TGLColor.Create(Self);
- FEdgeColor.Initialize(clrWhite);
- FGroupList := TGLListHandle.Create;
- CamInvarianceMode := cimNone;
- end;
- destructor TGLDummyCube.Destroy;
- begin
- FGroupList.Free;
- FEdgeColor.Free;
- inherited;
- end;
- procedure TGLDummyCube.Assign(Source: TPersistent);
- begin
- if Source is TGLDummyCube then
- begin
- FCubeSize := TGLDummyCube(Source).FCubeSize;
- FEdgeColor.Color := TGLDummyCube(Source).FEdgeColor.Color;
- FVisibleAtRunTime := TGLDummyCube(Source).FVisibleAtRunTime;
- NotifyChange(Self);
- end;
- inherited Assign(Source);
- end;
- function TGLDummyCube.AxisAlignedDimensionsUnscaled: TGLVector;
- begin
- Result.X := 0.5 * Abs(FCubeSize);
- Result.Y := Result.X;
- Result.Z := Result.X;
- Result.W := 0;
- end;
- function TGLDummyCube.RayCastIntersect(const rayStart, rayVector: TGLVector;
- intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil): Boolean;
- begin
- Result := False;
- end;
- procedure TGLDummyCube.BuildList(var rci: TGLRenderContextInfo);
- begin
- if (csDesigning in ComponentState) or (FVisibleAtRunTime) then
- CubeWireframeBuildList(rci, FCubeSize, True, EdgeColor.Color);
- end;
- procedure TGLDummyCube.DoRender(var rci: TGLRenderContextInfo;
- renderSelf, renderChildren: Boolean);
- begin
- if Assigned(FOnVisibilityDetermination) then
- if not FOnVisibilityDetermination(Self, rci) then
- Exit;
- if FAmalgamate and (not rci.amalgamating) then
- begin
- if FGroupList.Handle = 0 then
- begin
- FGroupList.AllocateHandle;
- Assert(FGroupList.Handle <> 0, 'Handle=0 for ' + ClassName);
- rci.GLStates.NewList(FGroupList.Handle, GL_COMPILE);
- rci.amalgamating := True;
- // try
- inherited;
- // finally
- rci.amalgamating := False;
- rci.GLStates.EndList;
- // end;
- end;
- rci.GLStates.CallList(FGroupList.Handle);
- end
- else
- begin
- // proceed as usual
- inherited;
- end;
- end;
- procedure TGLDummyCube.StructureChanged;
- begin
- if FAmalgamate then
- FGroupList.DestroyHandle;
- inherited;
- end;
- function TGLDummyCube.BarycenterAbsolutePosition: TGLVector;
- var
- i: Integer;
- begin
- if Count > 0 then
- begin
- Result := Children[0].BarycenterAbsolutePosition;
- for i := 1 to Count - 1 do
- Result := VectorAdd(Result, Children[i].BarycenterAbsolutePosition);
- ScaleVector(Result, 1 / Count);
- end
- else
- Result := AbsolutePosition;
- end;
- procedure TGLDummyCube.SetCubeSize(const val: TGLFloat);
- begin
- if val <> FCubeSize then
- begin
- FCubeSize := val;
- StructureChanged;
- end;
- end;
- procedure TGLDummyCube.SetEdgeColor(const val: TGLColor);
- begin
- if val <> FEdgeColor then
- begin
- FEdgeColor.Assign(val);
- StructureChanged;
- end;
- end;
- procedure TGLDummyCube.SetVisibleAtRunTime(const val: Boolean);
- begin
- if val <> FVisibleAtRunTime then
- begin
- FVisibleAtRunTime := val;
- StructureChanged;
- end;
- end;
- procedure TGLDummyCube.SetAmalgamate(const val: Boolean);
- begin
- if val <> FAmalgamate then
- begin
- FAmalgamate := val;
- if not val then
- FGroupList.DestroyHandle;
- inherited StructureChanged;
- end;
- end;
- // ------------------
- // ------------------ TGLPlane ------------------
- // ------------------
- constructor TGLPlane.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- FWidth := 1;
- FHeight := 1;
- FXTiles := 1;
- FYTiles := 1;
- FXScope := 1;
- FYScope := 1;
- ObjectStyle := ObjectStyle + [osDirectDraw];
- FStyle := [psSingleQuad, psTileTexture];
- end;
- procedure TGLPlane.Assign(Source: TPersistent);
- begin
- if Assigned(Source) and (Source is TGLPlane) then
- begin
- FWidth := TGLPlane(Source).FWidth;
- FHeight := TGLPlane(Source).FHeight;
- FXOffset := TGLPlane(Source).FXOffset;
- FXScope := TGLPlane(Source).FXScope;
- FXTiles := TGLPlane(Source).FXTiles;
- FYOffset := TGLPlane(Source).FYOffset;
- FYScope := TGLPlane(Source).FYScope;
- FYTiles := TGLPlane(Source).FYTiles;
- FStyle := TGLPlane(Source).FStyle;
- StructureChanged;
- end;
- inherited Assign(Source);
- end;
- function TGLPlane.AxisAlignedDimensionsUnscaled: TGLVector;
- begin
- Result.X := 0.5 * Abs(FWidth);
- Result.Y := 0.5 * Abs(FHeight);
- Result.Z := 0;
- end;
- function TGLPlane.RayCastIntersect(const rayStart, rayVector: TGLVector;
- intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil): Boolean;
- var
- locRayStart, locRayVector, ip: TGLVector;
- t: Single;
- begin
- locRayStart := AbsoluteToLocal(rayStart);
- locRayVector := AbsoluteToLocal(rayVector);
- if locRayStart.Z >= 0 then
- begin
- // ray start over plane
- if locRayVector.Z < 0 then
- begin
- t := locRayStart.Z / locRayVector.Z;
- ip.X := locRayStart.X - t * locRayVector.X;
- ip.Y := locRayStart.Y - t * locRayVector.Y;
- if (Abs(ip.X) <= 0.5 * Width) and (Abs(ip.Y) <= 0.5 * Height) then
- begin
- Result := True;
- if Assigned(intersectNormal) then
- intersectNormal^ := AbsoluteDirection;
- end
- else
- Result := False;
- end
- else
- Result := False;
- end
- else
- begin
- // ray start below plane
- if locRayVector.Z > 0 then
- begin
- t := locRayStart.Z / locRayVector.Z;
- ip.X := locRayStart.X - t * locRayVector.X;
- ip.Y := locRayStart.Y - t * locRayVector.Y;
- if (Abs(ip.X) <= 0.5 * Width) and (Abs(ip.Y) <= 0.5 * Height) then
- begin
- Result := True;
- if Assigned(intersectNormal) then
- intersectNormal^ := VectorNegate(AbsoluteDirection);
- end
- else
- Result := False;
- end
- else
- Result := False;
- end;
- if Result and Assigned(intersectPoint) then
- begin
- ip.Z := 0;
- ip.W := 1;
- intersectPoint^ := LocalToAbsolute(ip);
- end;
- end;
- function TGLPlane.GenerateSilhouette(const silhouetteParameters
- : TGLSilhouetteParameters): TGLSilhouette;
- var
- hw, hh: Single;
- begin
- Result := TGLSilhouette.Create;
- hw := FWidth * 0.5;
- hh := FHeight * 0.5;
- with Result.vertices do
- begin
- AddPoint(hw, hh);
- AddPoint(hw, -hh);
- AddPoint(-hw, -hh);
- AddPoint(-hw, hh);
- end;
- with Result.Indices do
- begin
- Add(0, 1);
- Add(1, 2);
- Add(2, 3);
- Add(3, 0);
- end;
- if silhouetteParameters.CappingRequired then
- with Result.CapIndices do
- begin
- Add(0, 1, 2);
- Add(2, 3, 0);
- end;
- end;
- procedure TGLPlane.BuildList(var rci: TGLRenderContextInfo);
- procedure EmitVertex(ptr: PGLVertexRec); inline;
- begin
- xgl.TexCoord2fv(@ptr^.TexCoord);
- gl.Vertex3fv(@ptr^.Position);
- end;
- var
- hw, hh, posXFact, posYFact, pX, pY1: TGLFloat;
- tx0, tx1, ty0, ty1, texSFact, texTFact: TGLFloat;
- texS, texT1: TGLFloat;
- X, Y: Integer;
- TanLoc, BinLoc: Integer;
- pVertex: PGLVertexRec;
- begin
- hw := FWidth * 0.5;
- hh := FHeight * 0.5;
- gl.Normal3fv(@ZVector);
- if GL.ARB_shader_objects and (rci.GLStates.CurrentProgram > 0) then
- begin
- TanLoc := gl.GetAttribLocation(rci.GLStates.CurrentProgram,
- TangentAttributeName);
- BinLoc := gl.GetAttribLocation(rci.GLStates.CurrentProgram,
- BinormalAttributeName);
- if TanLoc > -1 then
- gl.VertexAttrib3fv(TanLoc, @XVector);
- if BinLoc > -1 then
- gl.VertexAttrib3fv(BinLoc, @YVector);
- end;
- // determine tex coords extents
- if psTileTexture in FStyle then
- begin
- tx0 := FXOffset;
- tx1 := FXTiles * FXScope + FXOffset;
- ty0 := FYOffset;
- ty1 := FYTiles * FYScope + FYOffset;
- end
- else
- begin
- tx0 := 0;
- ty0 := tx0;
- tx1 := FXScope;
- ty1 := FYScope;
- end;
- if psSingleQuad in FStyle then
- begin
- // single quad plane
- gl.Begin_(GL_TRIANGLES);
- xgl.TexCoord2f(tx1, ty1);
- gl.Vertex2f(hw, hh);
- xgl.TexCoord2f(tx0, ty1);
- gl.Vertex2f(-hw, hh);
- xgl.TexCoord2f(tx0, ty0);
- gl.Vertex2f(-hw, -hh);
- gl.Vertex2f(-hw, -hh);
- xgl.TexCoord2f(tx1, ty0);
- gl.Vertex2f(hw, -hh);
- xgl.TexCoord2f(tx1, ty1);
- gl.Vertex2f(hw, hh);
- gl.End_;
- Exit;
- end
- else
- begin
- // multi-quad plane (actually built from tri-strips)
- texSFact := (tx1 - tx0) / FXTiles;
- texTFact := (ty1 - ty0) / FYTiles;
- posXFact := FWidth / FXTiles;
- posYFact := FHeight / FYTiles;
- if FMesh = nil then
- begin
- SetLength(FMesh, FYTiles + 1, FXTiles + 1);
- for Y := 0 to FYTiles do
- begin
- texT1 := Y * texTFact;
- pY1 := Y * posYFact - hh;
- for X := 0 to FXTiles do
- begin
- texS := X * texSFact;
- pX := X * posXFact - hw;
- FMesh[Y][X].Position := Vector3fMake(pX, pY1, 0.0);
- FMesh[Y][X].TexCoord := Vector2fMake(texS, texT1);
- end;
- end;
- end;
- end;
- gl.Begin_(GL_TRIANGLES);
- for Y := 0 to FYTiles - 1 do
- begin
- for X := 0 to FXTiles - 1 do
- begin
- pVertex := @FMesh[Y][X];
- EmitVertex(pVertex);
- pVertex := @FMesh[Y][X + 1];
- EmitVertex(pVertex);
- pVertex := @FMesh[Y + 1][X];
- EmitVertex(pVertex);
- pVertex := @FMesh[Y + 1][X + 1];
- EmitVertex(pVertex);
- pVertex := @FMesh[Y + 1][X];
- EmitVertex(pVertex);
- pVertex := @FMesh[Y][X + 1];
- EmitVertex(pVertex);
- end;
- end;
- gl.End_;
- end;
- procedure TGLPlane.SetWidth(const aValue: Single);
- begin
- if aValue <> FWidth then
- begin
- FWidth := aValue;
- FMesh := nil;
- StructureChanged;
- end;
- end;
- function TGLPlane.ScreenRect(aBuffer: TGLSceneBuffer): TRect;
- var
- v: array [0 .. 3] of TGLVector;
- buf: TGLSceneBuffer;
- hw, hh: TGLFloat;
- begin
- buf := aBuffer;
- if Assigned(buf) then
- begin
- hw := FWidth * 0.5;
- hh := FHeight * 0.5;
- v[0] := LocalToAbsolute(PointMake(-hw, -hh, 0));
- v[1] := LocalToAbsolute(PointMake(hw, -hh, 0));
- v[2] := LocalToAbsolute(PointMake(hw, hh, 0));
- v[3] := LocalToAbsolute(PointMake(-hw, hh, 0));
- buf.WorldToScreen(@v[0], 4);
- Result.Left := Round(MinFloat([v[0].X, v[1].X, v[2].X, v[3].X]));
- Result.Right := Round(MaxFloat([v[0].X, v[1].X, v[2].X, v[3].X]));
- Result.Top := Round(MinFloat([v[0].Y, v[1].Y, v[2].Y, v[3].Y]));
- Result.Bottom := Round(MaxFloat([v[0].Y, v[1].Y, v[2].Y, v[3].Y]));
- end
- else
- FillChar(Result, SizeOf(TRect), 0);
- end;
- function TGLPlane.PointDistance(const aPoint: TGLVector): Single;
- begin
- Result := VectorDotProduct(VectorSubtract(aPoint, AbsolutePosition),
- AbsoluteDirection);
- end;
- procedure TGLPlane.SetHeight(const aValue: Single);
- begin
- if aValue <> FHeight then
- begin
- FHeight := aValue;
- FMesh := nil;
- StructureChanged;
- end;
- end;
- procedure TGLPlane.SetXOffset(const Value: TGLFloat);
- begin
- if Value <> FXOffset then
- begin
- FXOffset := Value;
- FMesh := nil;
- StructureChanged;
- end;
- end;
- procedure TGLPlane.SetXScope(const Value: TGLFloat);
- begin
- if Value <> FXScope then
- begin
- FXScope := Value;
- if FXScope > 1 then
- FXScope := 1;
- FMesh := nil;
- StructureChanged;
- end;
- end;
- function TGLPlane.StoreXScope: Boolean;
- begin
- Result := (FXScope <> 1);
- end;
- procedure TGLPlane.SetXTiles(const Value: Cardinal);
- begin
- if Value <> FXTiles then
- begin
- FXTiles := Value;
- FMesh := nil;
- StructureChanged;
- end;
- end;
- procedure TGLPlane.SetYOffset(const Value: TGLFloat);
- begin
- if Value <> FYOffset then
- begin
- FYOffset := Value;
- FMesh := nil;
- StructureChanged;
- end;
- end;
- procedure TGLPlane.SetYScope(const Value: TGLFloat);
- begin
- if Value <> FYScope then
- begin
- FYScope := Value;
- if FYScope > 1 then
- FYScope := 1;
- FMesh := nil;
- StructureChanged;
- end;
- end;
- function TGLPlane.StoreYScope: Boolean;
- begin
- Result := (FYScope <> 1);
- end;
- procedure TGLPlane.SetYTiles(const Value: Cardinal);
- begin
- if Value <> FYTiles then
- begin
- FYTiles := Value;
- FMesh := nil;
- StructureChanged;
- end;
- end;
- procedure TGLPlane.SetStyle(const val: TGLPlaneStyles);
- begin
- if val <> FStyle then
- begin
- FStyle := val;
- StructureChanged;
- end;
- end;
- // ------------------
- // ------------------ TGLSprite ------------------
- // ------------------
- constructor TGLSprite.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- ObjectStyle := ObjectStyle + [osDirectDraw, osNoVisibilityCulling];
- FAlphaChannel := 1;
- FWidth := 1;
- FHeight := 1;
- end;
- procedure TGLSprite.Assign(Source: TPersistent);
- begin
- if Source is TGLSprite then
- begin
- FWidth := TGLSprite(Source).FWidth;
- FHeight := TGLSprite(Source).FHeight;
- FRotation := TGLSprite(Source).FRotation;
- FAlphaChannel := TGLSprite(Source).FAlphaChannel;
- end;
- inherited Assign(Source);
- end;
- function TGLSprite.AxisAlignedDimensionsUnscaled: TGLVector;
- begin
- Result.X := 0.5 * Abs(FWidth);
- Result.Y := 0.5 * Abs(FHeight);
- // Sprites turn with the camera and can be considered to have the same depth
- // as width
- Result.Z := 0.5 * Abs(FWidth);
- end;
- procedure TGLSprite.BuildList(var rci: TGLRenderContextInfo);
- var
- vx, vy: TAffineVector;
- W, h: Single;
- mat: TGLMatrix;
- u0, v0, u1, v1: Integer;
- begin
- if FAlphaChannel <> 1 then
- rci.GLStates.SetGLMaterialAlphaChannel(GL_FRONT, FAlphaChannel);
- mat := rci.PipelineTransformation.ModelViewMatrix^;
- // extraction of the direction vectors of the matrix
- W := FWidth * 0.5;
- h := FHeight * 0.5;
- vx.X := mat.v[0].X;
- vy.X := mat.v[0].Y;
- vx.Y := mat.v[1].X;
- vy.Y := mat.v[1].Y;
- vx.Z := mat.v[2].X;
- vy.Z := mat.v[2].Y;
- ScaleVector(vx, W / VectorLength(vx));
- ScaleVector(vy, h / VectorLength(vy));
- if FMirrorU then
- begin
- u0 := 1;
- u1 := 0;
- end
- else
- begin
- u0 := 0;
- u1 := 1;
- end;
- if FMirrorV then
- begin
- v0 := 1;
- v1 := 0;
- end
- else
- begin
- v0 := 0;
- v1 := 1;
- end;
- if FRotation <> 0 then
- begin
- gl.PushMatrix;
- gl.Rotatef(FRotation, mat.v[0].Z, mat.v[1].Z, mat.v[2].Z);
- end;
- gl.Begin_(GL_QUADS);
- xgl.TexCoord2f(u1, v1);
- gl.Vertex3f(vx.X + vy.X, vx.Y + vy.Y, vx.Z + vy.Z);
- xgl.TexCoord2f(u0, v1);
- gl.Vertex3f(-vx.X + vy.X, -vx.Y + vy.Y, -vx.Z + vy.Z);
- xgl.TexCoord2f(u0, v0);
- gl.Vertex3f(-vx.X - vy.X, -vx.Y - vy.Y, -vx.Z - vy.Z);
- xgl.TexCoord2f(u1, v0);
- gl.Vertex3f(vx.X - vy.X, vx.Y - vy.Y, vx.Z - vy.Z);
- gl.End_;
- if FRotation <> 0 then
- gl.PopMatrix;
- end;
- procedure TGLSprite.SetWidth(const val: TGLFloat);
- begin
- if FWidth <> val then
- begin
- FWidth := val;
- NotifyChange(Self);
- end;
- end;
- procedure TGLSprite.SetHeight(const val: TGLFloat);
- begin
- if FHeight <> val then
- begin
- FHeight := val;
- NotifyChange(Self);
- end;
- end;
- procedure TGLSprite.SetRotation(const val: TGLFloat);
- begin
- if FRotation <> val then
- begin
- FRotation := val;
- NotifyChange(Self);
- end;
- end;
- procedure TGLSprite.SetAlphaChannel(const val: Single);
- begin
- if val <> FAlphaChannel then
- begin
- if val < 0 then
- FAlphaChannel := 0
- else if val > 1 then
- FAlphaChannel := 1
- else
- FAlphaChannel := val;
- NotifyChange(Self);
- end;
- end;
- function TGLSprite.StoreAlphaChannel: Boolean;
- begin
- Result := (FAlphaChannel <> 1);
- end;
- procedure TGLSprite.SetMirrorU(const val: Boolean);
- begin
- FMirrorU := val;
- NotifyChange(Self);
- end;
- procedure TGLSprite.SetMirrorV(const val: Boolean);
- begin
- FMirrorV := val;
- NotifyChange(Self);
- end;
- procedure TGLSprite.SetSize(const Width, Height: TGLFloat);
- begin
- FWidth := Width;
- FHeight := Height;
- NotifyChange(Self);
- end;
- procedure TGLSprite.SetSquareSize(const Size: TGLFloat);
- begin
- FWidth := Size;
- FHeight := Size;
- NotifyChange(Self);
- end;
- // ------------------
- // ------------------ TGLPointParameters ------------------
- // ------------------
- constructor TGLPointParameters.Create(AOwner: TPersistent);
- begin
- inherited Create(AOwner);
- FMinSize := 0;
- FMaxSize := 128;
- FFadeTresholdSize := 1;
- FDistanceAttenuation := TGLCoordinates.CreateInitialized(Self, XHmgVector,
- csVector);
- end;
- destructor TGLPointParameters.Destroy;
- begin
- FDistanceAttenuation.Free;
- inherited;
- end;
- procedure TGLPointParameters.Assign(Source: TPersistent);
- begin
- if Source is TGLPointParameters then
- begin
- FMinSize := TGLPointParameters(Source).FMinSize;
- FMaxSize := TGLPointParameters(Source).FMaxSize;
- FFadeTresholdSize := TGLPointParameters(Source).FFadeTresholdSize;
- FDistanceAttenuation.Assign(TGLPointParameters(Source).DistanceAttenuation);
- end;
- end;
- procedure TGLPointParameters.DefineProperties(Filer: TFiler);
- var
- defaultParams: Boolean;
- begin
- inherited;
- defaultParams := (FMaxSize = 128) and (FMinSize = 0) and
- (FFadeTresholdSize = 1);
- Filer.DefineBinaryProperty('PointParams', ReadData, WriteData,
- not defaultParams);
- end;
- procedure TGLPointParameters.ReadData(Stream: TStream);
- begin
- with Stream do
- begin
- Read(FMinSize, SizeOf(Single));
- Read(FMaxSize, SizeOf(Single));
- Read(FFadeTresholdSize, SizeOf(Single));
- end;
- end;
- procedure TGLPointParameters.WriteData(Stream: TStream);
- begin
- with Stream do
- begin
- Write(FMinSize, SizeOf(Single));
- Write(FMaxSize, SizeOf(Single));
- Write(FFadeTresholdSize, SizeOf(Single));
- end;
- end;
- procedure TGLPointParameters.Apply;
- begin
- if Enabled and GL.ARB_point_parameters then
- begin
- gl.PointParameterf(GL_POINT_SIZE_MIN_ARB, FMinSize);
- gl.PointParameterf(GL_POINT_SIZE_MAX_ARB, FMaxSize);
- gl.PointParameterf(GL_POINT_FADE_THRESHOLD_SIZE_ARB, FFadeTresholdSize);
- gl.PointParameterfv(GL_DISTANCE_ATTENUATION_EXT,
- FDistanceAttenuation.AsAddress);
- end;
- end;
- procedure TGLPointParameters.UnApply;
- begin
- if Enabled and GL.ARB_point_parameters then
- begin
- gl.PointParameterf(GL_POINT_SIZE_MIN_ARB, 0);
- gl.PointParameterf(GL_POINT_SIZE_MAX_ARB, 128);
- gl.PointParameterf(GL_POINT_FADE_THRESHOLD_SIZE_ARB, 1);
- gl.PointParameterfv(GL_DISTANCE_ATTENUATION_EXT, @XVector);
- end;
- end;
- procedure TGLPointParameters.SetEnabled(const val: Boolean);
- begin
- if val <> FEnabled then
- begin
- FEnabled := val;
- NotifyChange(Self);
- end;
- end;
- procedure TGLPointParameters.SetMinSize(const val: Single);
- begin
- if val <> FMinSize then
- begin
- if val < 0 then
- FMinSize := 0
- else
- FMinSize := val;
- NotifyChange(Self);
- end;
- end;
- procedure TGLPointParameters.SetMaxSize(const val: Single);
- begin
- if val <> FMaxSize then
- begin
- if val < 0 then
- FMaxSize := 0
- else
- FMaxSize := val;
- NotifyChange(Self);
- end;
- end;
- procedure TGLPointParameters.SetFadeTresholdSize(const val: Single);
- begin
- if val <> FFadeTresholdSize then
- begin
- if val < 0 then
- FFadeTresholdSize := 0
- else
- FFadeTresholdSize := val;
- NotifyChange(Self);
- end;
- end;
- procedure TGLPointParameters.SetDistanceAttenuation(const val: TGLCoordinates);
- begin
- FDistanceAttenuation.Assign(val);
- end;
- // ------------------
- // ------------------ TGLPoints ------------------
- // ------------------
- constructor TGLPoints.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- ObjectStyle := ObjectStyle + [osDirectDraw, osNoVisibilityCulling];
- FStyle := psSquare;
- FSize := cDefaultPointSize;
- FPositions := TGLAffineVectorList.Create;
- FPositions.Add(NullVector);
- FColors := TGLVectorList.Create;
- FPointParameters := TGLPointParameters.Create(Self);
- end;
- destructor TGLPoints.Destroy;
- begin
- FPointParameters.Free;
- FColors.Free;
- FPositions.Free;
- inherited;
- end;
- procedure TGLPoints.Assign(Source: TPersistent);
- begin
- if Source is TGLPoints then
- begin
- FSize := TGLPoints(Source).FSize;
- FStyle := TGLPoints(Source).FStyle;
- FPositions.Assign(TGLPoints(Source).FPositions);
- FColors.Assign(TGLPoints(Source).FColors);
- StructureChanged
- end;
- inherited Assign(Source);
- end;
- procedure TGLPoints.BuildList(var rci: TGLRenderContextInfo);
- var
- n: Integer;
- v: TGLVector;
- begin
- n := FPositions.Count;
- if n = 0 then
- Exit;
- case FColors.Count of
- 0:
- gl.Color4f(1, 1, 1, 1);
- 1:
- gl.Color4fv(PGLFloat(FColors.List));
- else
- if FColors.Count < n then
- n := FColors.Count;
- gl.ColorPointer(4, GL_FLOAT, 0, FColors.List);
- gl.EnableClientState(GL_COLOR_ARRAY);
- end;
- if FColors.Count < 2 then
- gl.DisableClientState(GL_COLOR_ARRAY);
- rci.GLStates.Disable(stLighting);
- if n = 0 then
- begin
- v := NullHmgPoint;
- gl.VertexPointer(3, GL_FLOAT, 0, @v);
- n := 1;
- end
- else
- gl.VertexPointer(3, GL_FLOAT, 0, FPositions.List);
- gl.EnableClientState(GL_VERTEX_ARRAY);
- if NoZWrite then
- rci.GLStates.DepthWriteMask := False;
- rci.GLStates.PointSize := FSize;
- PointParameters.Apply;
- if GL.EXT_compiled_vertex_array and (n > 64) then
- gl.LockArrays(0, n);
- case FStyle of
- psSquare:
- begin
- // square point (simplest method, fastest)
- rci.GLStates.Disable(stBlend);
- end;
- psRound:
- begin
- rci.GLStates.Enable(stPointSmooth);
- rci.GLStates.Enable(stAlphaTest);
- rci.GLStates.SetGLAlphaFunction(cfGreater, 0.5);
- rci.GLStates.Disable(stBlend);
- end;
- psSmooth:
- begin
- rci.GLStates.Enable(stPointSmooth);
- rci.GLStates.Enable(stAlphaTest);
- rci.GLStates.SetGLAlphaFunction(cfNotEqual, 0.0);
- rci.GLStates.Enable(stBlend);
- rci.GLStates.SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
- end;
- psSmoothAdditive:
- begin
- rci.GLStates.Enable(stPointSmooth);
- rci.GLStates.Enable(stAlphaTest);
- rci.GLStates.SetGLAlphaFunction(cfNotEqual, 0.0);
- rci.GLStates.Enable(stBlend);
- rci.GLStates.SetBlendFunc(bfSrcAlpha, bfOne);
- end;
- psSquareAdditive:
- begin
- rci.GLStates.Enable(stBlend);
- rci.GLStates.SetBlendFunc(bfSrcAlpha, bfOne);
- end;
- else
- Assert(False);
- end;
- gl.DrawArrays(GL_POINTS, 0, n);
- if GL.EXT_compiled_vertex_array and (n > 64) then
- gl.UnlockArrays;
- PointParameters.UnApply;
- gl.DisableClientState(GL_VERTEX_ARRAY);
- if FColors.Count > 1 then
- gl.DisableClientState(GL_COLOR_ARRAY);
- end;
- function TGLPoints.StoreSize: Boolean;
- begin
- Result := (FSize <> cDefaultPointSize);
- end;
- procedure TGLPoints.SetNoZWrite(const val: Boolean);
- begin
- if FNoZWrite <> val then
- begin
- FNoZWrite := val;
- StructureChanged;
- end;
- end;
- procedure TGLPoints.SetStatic(const val: Boolean);
- begin
- if FStatic <> val then
- begin
- FStatic := val;
- if val then
- ObjectStyle := ObjectStyle - [osDirectDraw]
- else
- ObjectStyle := ObjectStyle + [osDirectDraw];
- StructureChanged;
- end;
- end;
- procedure TGLPoints.SetSize(const val: Single);
- begin
- if FSize <> val then
- begin
- FSize := val;
- StructureChanged;
- end;
- end;
- procedure TGLPoints.SetPositions(const val: TGLAffineVectorList);
- begin
- FPositions.Assign(val);
- StructureChanged;
- end;
- procedure TGLPoints.SetColors(const val: TGLVectorList);
- begin
- FColors.Assign(val);
- StructureChanged;
- end;
- procedure TGLPoints.SetStyle(const val: TGLPointStyle);
- begin
- if FStyle <> val then
- begin
- FStyle := val;
- StructureChanged;
- end;
- end;
- procedure TGLPoints.SetPointParameters(const val: TGLPointParameters);
- begin
- FPointParameters.Assign(val);
- end;
- // ------------------
- // ------------------ TGLLineBase ------------------
- // ------------------
- constructor TGLLineBase.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- FLineColor := TGLColor.Create(Self);
- FLineColor.Initialize(clrWhite);
- FLinePattern := $FFFF;
- FAntiAliased := False;
- FLineWidth := 1.0;
- end;
- destructor TGLLineBase.Destroy;
- begin
- FLineColor.Free;
- inherited Destroy;
- end;
- procedure TGLLineBase.NotifyChange(Sender: TObject);
- begin
- if Sender = FLineColor then
- StructureChanged;
- inherited;
- end;
- procedure TGLLineBase.SetLineColor(const Value: TGLColor);
- begin
- FLineColor.Color := Value.Color;
- StructureChanged;
- end;
- procedure TGLLineBase.SetLinePattern(const Value: TGLushort);
- begin
- if FLinePattern <> Value then
- begin
- FLinePattern := Value;
- StructureChanged;
- end;
- end;
- procedure TGLLineBase.SetLineWidth(const val: Single);
- begin
- if FLineWidth <> val then
- begin
- FLineWidth := val;
- StructureChanged;
- end;
- end;
- function TGLLineBase.StoreLineWidth: Boolean;
- begin
- Result := (FLineWidth <> 1.0);
- end;
- procedure TGLLineBase.SetAntiAliased(const val: Boolean);
- begin
- if FAntiAliased <> val then
- begin
- FAntiAliased := val;
- StructureChanged;
- end;
- end;
- procedure TGLLineBase.Assign(Source: TPersistent);
- begin
- if Source is TGLLineBase then
- begin
- LineColor := TGLLineBase(Source).FLineColor;
- LinePattern := TGLLineBase(Source).FLinePattern;
- LineWidth := TGLLineBase(Source).FLineWidth;
- AntiAliased := TGLLineBase(Source).FAntiAliased;
- end;
- inherited Assign(Source);
- end;
- procedure TGLLineBase.SetupLineStyle(var rci: TGLRenderContextInfo);
- begin
- with rci.GLStates do
- begin
- Disable(stLighting);
- if FLinePattern <> $FFFF then
- begin
- Enable(stLineStipple);
- Enable(stBlend);
- SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
- LineStippleFactor := 1;
- LineStipplePattern := FLinePattern;
- end
- else
- Disable(stLineStipple);
- if FAntiAliased then
- begin
- Enable(stLineSmooth);
- Enable(stBlend);
- SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
- end
- else
- Disable(stLineSmooth);
- LineWidth := FLineWidth;
- if FLineColor.Alpha <> 1 then
- begin
- if not FAntiAliased then
- begin
- Enable(stBlend);
- SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
- end;
- gl.Color4fv(FLineColor.AsAddress);
- end
- else
- gl.Color3fv(FLineColor.AsAddress);
- end;
- end;
- // ------------------
- // ------------------ TGLLinesNode ------------------
- // ------------------
- constructor TGLLinesNode.Create(Collection: TCollection);
- begin
- inherited Create(Collection);
- FColor := TGLColor.Create(Self);
- FColor.Initialize((TGLLinesNodes(Collection).GetOwner as TGLLines)
- .NodeColor.Color);
- FColor.OnNotifyChange := OnColorChange;
- end;
- destructor TGLLinesNode.Destroy;
- begin
- FColor.Free;
- inherited Destroy;
- end;
- procedure TGLLinesNode.Assign(Source: TPersistent);
- begin
- if Source is TGLLinesNode then
- FColor.Assign(TGLLinesNode(Source).FColor);
- inherited;
- end;
- procedure TGLLinesNode.SetColor(const val: TGLColor);
- begin
- FColor.Assign(val);
- end;
- procedure TGLLinesNode.OnColorChange(Sender: TObject);
- begin
- (Collection as TGLNodes).NotifyChange;
- end;
- function TGLLinesNode.StoreColor: Boolean;
- begin
- Result := not VectorEquals((TGLLinesNodes(Collection).GetOwner as TGLLines)
- .NodeColor.Color, FColor.Color);
- end;
- // ------------------
- // ------------------ TGLLinesNodes ------------------
- // ------------------
- constructor TGLLinesNodes.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner, TGLLinesNode);
- end;
- procedure TGLLinesNodes.NotifyChange;
- begin
- if (GetOwner <> nil) then
- (GetOwner as TGLBaseSceneObject).StructureChanged;
- end;
- // ------------------
- // ------------------ TGLNodedLines ------------------
- // ------------------
- constructor TGLNodedLines.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- FNodes := TGLLinesNodes.Create(Self);
- FNodeColor := TGLColor.Create(Self);
- FNodeColor.Initialize(clrBlue);
- FNodeColor.OnNotifyChange := OnNodeColorChanged;
- FOldNodeColor := clrBlue;
- FNodesAspect := lnaAxes;
- FNodeSize := 1;
- end;
- destructor TGLNodedLines.Destroy;
- begin
- FNodes.Free;
- FNodeColor.Free;
- inherited Destroy;
- end;
- procedure TGLNodedLines.SetNodesAspect(const Value: TGLLineNodesAspect);
- begin
- if Value <> FNodesAspect then
- begin
- FNodesAspect := Value;
- StructureChanged;
- end;
- end;
- procedure TGLNodedLines.SetNodeColor(const Value: TGLColor);
- begin
- FNodeColor.Color := Value.Color;
- StructureChanged;
- end;
- procedure TGLNodedLines.OnNodeColorChanged(Sender: TObject);
- var
- i: Integer;
- begin
- // update color for nodes...
- for i := 0 to Nodes.Count - 1 do
- if VectorEquals(TGLLinesNode(Nodes[i]).Color.Color, FOldNodeColor) then
- TGLLinesNode(Nodes[i]).Color.Assign(FNodeColor);
- SetVector(FOldNodeColor, FNodeColor.Color);
- end;
- procedure TGLNodedLines.SetNodes(const aNodes: TGLLinesNodes);
- begin
- FNodes.Free;
- FNodes := aNodes;
- StructureChanged;
- end;
- procedure TGLNodedLines.SetNodeSize(const val: Single);
- begin
- if val <= 0 then
- FNodeSize := 1
- else
- FNodeSize := val;
- StructureChanged;
- end;
- function TGLNodedLines.StoreNodeSize: Boolean;
- begin
- Result := FNodeSize <> 1;
- end;
- procedure TGLNodedLines.Assign(Source: TPersistent);
- begin
- if Source is TGLNodedLines then
- begin
- SetNodes(TGLNodedLines(Source).FNodes);
- FNodesAspect := TGLNodedLines(Source).FNodesAspect;
- FNodeColor.Color := TGLNodedLines(Source).FNodeColor.Color;
- FNodeSize := TGLNodedLines(Source).FNodeSize;
- end;
- inherited Assign(Source);
- end;
- procedure TGLNodedLines.DrawNode(var rci: TGLRenderContextInfo; X, Y, Z: Single;
- Color: TGLColor);
- begin
- gl.PushMatrix;
- gl.Translatef(X, Y, Z);
- case NodesAspect of
- lnaAxes:
- AxesBuildList(rci, $CCCC, FNodeSize * 0.5);
- lnaCube:
- CubeWireframeBuildList(rci, FNodeSize, False, Color.Color);
- else
- Assert(False)
- end;
- gl.PopMatrix;
- end;
- function TGLNodedLines.AxisAlignedDimensionsUnscaled: TGLVector;
- var
- i: Integer;
- begin
- RstVector(Result);
- for i := 0 to Nodes.Count - 1 do
- MaxVector(Result, VectorAbs(Nodes[i].AsVector));
- // EG: commented out, line below looks suspicious, since scale isn't taken
- // into account in previous loop, must have been hiding another bug... somewhere...
- // DivideVector(Result, Scale.AsVector); //DanB ?
- end;
- procedure TGLNodedLines.AddNode(const coords: TGLCoordinates);
- var
- n: TGLNode;
- begin
- n := Nodes.Add;
- if Assigned(coords) then
- n.AsVector := coords.AsVector;
- StructureChanged;
- end;
- procedure TGLNodedLines.AddNode(const X, Y, Z: TGLFloat);
- var
- n: TGLNode;
- begin
- n := Nodes.Add;
- n.AsVector := VectorMake(X, Y, Z, 1);
- StructureChanged;
- end;
- procedure TGLNodedLines.AddNode(const Value: TGLVector);
- var
- n: TGLNode;
- begin
- n := Nodes.Add;
- n.AsVector := Value;
- StructureChanged;
- end;
- procedure TGLNodedLines.AddNode(const Value: TAffineVector);
- var
- n: TGLNode;
- begin
- n := Nodes.Add;
- n.AsVector := VectorMake(Value);
- StructureChanged;
- end;
- // ------------------
- // ------------------ TGLLines ------------------
- // ------------------
- constructor TGLLines.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- FDivision := 10;
- FSplineMode := lsmLines;
- FNURBSKnots := TGLSingleList.Create;
- FNURBSOrder := 0;
- FNURBSTolerance := 50;
- end;
- destructor TGLLines.Destroy;
- begin
- FNURBSKnots.Free;
- inherited Destroy;
- end;
- procedure TGLLines.SetDivision(const Value: Integer);
- begin
- if Value <> FDivision then
- begin
- if Value < 1 then
- FDivision := 1
- else
- FDivision := Value;
- StructureChanged;
- end;
- end;
- procedure TGLLines.SetOptions(const val: TGLLinesOptions);
- begin
- FOptions := val;
- StructureChanged;
- end;
- procedure TGLLines.SetSplineMode(const val: TGLLineSplineMode);
- begin
- if FSplineMode <> val then
- begin
- FSplineMode := val;
- StructureChanged;
- end;
- end;
- procedure TGLLines.SetNURBSOrder(const val: Integer);
- begin
- if val <> FNURBSOrder then
- begin
- FNURBSOrder := val;
- StructureChanged;
- end;
- end;
- procedure TGLLines.SetNURBSTolerance(const val: Single);
- begin
- if val <> FNURBSTolerance then
- begin
- FNURBSTolerance := val;
- StructureChanged;
- end;
- end;
- procedure TGLLines.Assign(Source: TPersistent);
- begin
- if Source is TGLLines then
- begin
- FDivision := TGLLines(Source).FDivision;
- FSplineMode := TGLLines(Source).FSplineMode;
- FOptions := TGLLines(Source).FOptions;
- end;
- inherited Assign(Source);
- end;
- procedure TGLLines.BuildList(var rci: TGLRenderContextInfo);
- var
- i, n: Integer;
- A, B, C: TGLFloat;
- f: Single;
- Spline: TCubicSpline;
- vertexColor: TGLVector;
- nodeBuffer: array of TAffineVector;
- colorBuffer: array of TGLVector;
- nurbsRenderer: PGLUNurbs;
- begin
- if Nodes.Count > 1 then
- begin
- // first, we setup the line color & stippling styles
- SetupLineStyle(rci);
- if rci.bufferDepthTest then
- rci.GLStates.Enable(stDepthTest);
- if loColorLogicXor in Options then
- begin
- rci.GLStates.Enable(stColorLogicOp);
- rci.GLStates.LogicOpMode := loXOr;
- end;
- // Set up the control point buffer for Bezier splines and NURBS curves.
- // If required this could be optimized by storing a cached node buffer.
- if (FSplineMode = lsmBezierSpline) or (FSplineMode = lsmNURBSCurve) then
- begin
- SetLength(nodeBuffer, Nodes.Count);
- SetLength(colorBuffer, Nodes.Count);
- for i := 0 to Nodes.Count - 1 do
- with TGLLinesNode(Nodes[i]) do
- begin
- nodeBuffer[i] := AsAffineVector;
- colorBuffer[i] := Color.Color;
- end;
- end;
- if FSplineMode = lsmBezierSpline then
- begin
- // map evaluator
- rci.GLStates.PushAttrib([sttEval]);
- gl.Enable(GL_MAP1_VERTEX_3);
- gl.Enable(GL_MAP1_COLOR_4);
- gl.Map1f(GL_MAP1_VERTEX_3, 0, 1, 3, Nodes.Count, @nodeBuffer[0]);
- gl.Map1f(GL_MAP1_COLOR_4, 0, 1, 4, Nodes.Count, @colorBuffer[0]);
- end;
- // start drawing the line
- if (FSplineMode = lsmNURBSCurve) and (FDivision >= 2) then
- begin
- if (FNURBSOrder > 0) and (FNURBSKnots.Count > 0) then
- begin
- nurbsRenderer := gluNewNurbsRenderer;
- // try
- gluNurbsProperty(nurbsRenderer, GLU_SAMPLING_TOLERANCE,
- FNURBSTolerance);
- gluNurbsProperty(nurbsRenderer, GLU_DISPLAY_MODE, GLU_FILL);
- gluBeginCurve(nurbsRenderer);
- gluNurbsCurve(nurbsRenderer, FNURBSKnots.Count, @FNURBSKnots.List[0], 3,
- @nodeBuffer[0], FNURBSOrder, GL_MAP1_VERTEX_3);
- gluEndCurve(nurbsRenderer);
- // finally
- gluDeleteNurbsRenderer(nurbsRenderer);
- // end;
- end;
- end
- else
- begin
- // lines, cubic splines or bezier
- if FSplineMode = lsmSegments then
- gl.Begin_(GL_LINES)
- else if FSplineMode = lsmLoop then
- gl.Begin_(GL_LINE_LOOP)
- else
- gl.Begin_(GL_LINE_STRIP);
- if (FDivision < 2) or (FSplineMode in [lsmLines, lsmSegments, lsmLoop])
- then
- begin
- // standard line(s), draw directly
- if loUseNodeColorForLines in Options then
- begin
- // node color interpolation
- for i := 0 to Nodes.Count - 1 do
- with TGLLinesNode(Nodes[i]) do
- begin
- gl.Color4fv(Color.AsAddress);
- gl.Vertex3f(X, Y, Z);
- end;
- end
- else
- begin
- // single color
- for i := 0 to Nodes.Count - 1 do
- with Nodes[i] do
- gl.Vertex3f(X, Y, Z);
- end;
- end
- else if FSplineMode = lsmCubicSpline then
- begin
- // cubic spline
- Spline := Nodes.CreateNewCubicSpline;
- // try
- f := 1 / FDivision;
- for i := 0 to (Nodes.Count - 1) * FDivision do
- begin
- Spline.SplineXYZ(i * f, A, B, C);
- if loUseNodeColorForLines in Options then
- begin
- n := (i div FDivision);
- if n < Nodes.Count - 1 then
- VectorLerp(TGLLinesNode(Nodes[n]).Color.Color,
- TGLLinesNode(Nodes[n + 1]).Color.Color, (i mod FDivision) * f,
- vertexColor)
- else
- SetVector(vertexColor, TGLLinesNode(Nodes[Nodes.Count - 1])
- .Color.Color);
- gl.Color4fv(@vertexColor);
- end;
- gl.Vertex3f(A, B, C);
- end;
- // finally
- Spline.Free;
- // end;
- end
- else if FSplineMode = lsmBezierSpline then
- begin
- f := 1 / FDivision;
- for i := 0 to FDivision do
- gl.EvalCoord1f(i * f);
- end;
- gl.End_;
- end;
- rci.GLStates.Disable(stColorLogicOp);
- if FSplineMode = lsmBezierSpline then
- rci.GLStates.PopAttrib;
- if Length(nodeBuffer) > 0 then
- begin
- SetLength(nodeBuffer, 0);
- SetLength(colorBuffer, 0);
- end;
- if FNodesAspect <> lnaInvisible then
- begin
- if not rci.ignoreBlendingRequests then
- begin
- rci.GLStates.Enable(stBlend);
- rci.GLStates.SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
- end;
- for i := 0 to Nodes.Count - 1 do
- with TGLLinesNode(Nodes[i]) do
- DrawNode(rci, X, Y, Z, Color);
- end;
- end;
- end;
- // ------------------
- // ------------------ TGLCube ------------------
- // ------------------
- constructor TGLCube.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- FCubeSize := XYZVector;
- FParts := [cpTop, cpBottom, cpFront, cpBack, cpLeft, cpRight];
- FNormalDirection := ndOutside;
- ObjectStyle := ObjectStyle + [osDirectDraw];
- end;
- procedure TGLCube.BuildList(var rci: TGLRenderContextInfo);
- var
- v1: TAffineVector;
- v2: TAffineVector;
- v1d: TAffineVector;
- v2d: TAffineVector;
- nd: TGLFloat;
- TanLoc, BinLoc: Integer;
- begin
- VectorScale(FCubeSize, 0.5, v2);
- v1 := VectorNegate(v2);
- if FNormalDirection = ndInside then
- begin
- v1d := v2;
- v2d := v1;
- nd := -1
- end
- else
- begin
- v1d := v1;
- v2d := v2;
- nd := 1;
- end;
- if GL.ARB_shader_objects and (rci.GLStates.CurrentProgram > 0) then
- begin
- TanLoc := gl.GetAttribLocation(rci.GLStates.CurrentProgram,
- TangentAttributeName);
- BinLoc := gl.GetAttribLocation(rci.GLStates.CurrentProgram,
- BinormalAttributeName);
- end
- else
- begin
- TanLoc := -1;
- BinLoc := -1;
- end;
- gl.Begin_(GL_QUADS);
- if cpFront in FParts then
- begin
- gl.Normal3f(0, 0, nd);
- if TanLoc > -1 then
- gl.VertexAttrib3f(TanLoc, nd, 0, 0);
- if BinLoc > -1 then
- gl.VertexAttrib3f(BinLoc, 0, nd, 0);
- xgl.TexCoord2fv(@XYTexPoint);
- gl.Vertex3fv(@v2);
- xgl.TexCoord2fv(@YTexPoint);
- gl.Vertex3f(v1d.X, v2d.Y, v2.Z);
- xgl.TexCoord2fv(@NullTexPoint);
- gl.Vertex3f(v1.X, v1.Y, v2.Z);
- xgl.TexCoord2fv(@XTexPoint);
- gl.Vertex3f(v2d.X, v1d.Y, v2.Z);
- end;
- if cpBack in FParts then
- begin
- gl.Normal3f(0, 0, -nd);
- if TanLoc > -1 then
- gl.VertexAttrib3f(TanLoc, -nd, 0, 0);
- if BinLoc > -1 then
- gl.VertexAttrib3f(BinLoc, 0, nd, 0);
- xgl.TexCoord2fv(@YTexPoint);
- gl.Vertex3f(v2.X, v2.Y, v1.Z);
- xgl.TexCoord2fv(@NullTexPoint);
- gl.Vertex3f(v2d.X, v1d.Y, v1.Z);
- xgl.TexCoord2fv(@XTexPoint);
- gl.Vertex3fv(@v1);
- xgl.TexCoord2fv(@XYTexPoint);
- gl.Vertex3f(v1d.X, v2d.Y, v1.Z);
- end;
- if cpLeft in FParts then
- begin
- gl.Normal3f(-nd, 0, 0);
- if TanLoc > -1 then
- gl.VertexAttrib3f(TanLoc, 0, 0, nd);
- if BinLoc > -1 then
- gl.VertexAttrib3f(BinLoc, 0, nd, 0);
- xgl.TexCoord2fv(@XYTexPoint);
- gl.Vertex3f(v1.X, v2.Y, v2.Z);
- xgl.TexCoord2fv(@YTexPoint);
- gl.Vertex3f(v1.X, v2d.Y, v1d.Z);
- xgl.TexCoord2fv(@NullTexPoint);
- gl.Vertex3fv(@v1);
- xgl.TexCoord2fv(@XTexPoint);
- gl.Vertex3f(v1.X, v1d.Y, v2d.Z);
- end;
- if cpRight in FParts then
- begin
- gl.Normal3f(nd, 0, 0);
- if TanLoc > -1 then
- gl.VertexAttrib3f(TanLoc, 0, 0, -nd);
- if BinLoc > -1 then
- gl.VertexAttrib3f(BinLoc, 0, nd, 0);
- xgl.TexCoord2fv(@YTexPoint);
- gl.Vertex3fv(@v2);
- xgl.TexCoord2fv(@NullTexPoint);
- gl.Vertex3f(v2.X, v1d.Y, v2d.Z);
- xgl.TexCoord2fv(@XTexPoint);
- gl.Vertex3f(v2.X, v1.Y, v1.Z);
- xgl.TexCoord2fv(@XYTexPoint);
- gl.Vertex3f(v2.X, v2d.Y, v1d.Z);
- end;
- if cpTop in FParts then
- begin
- gl.Normal3f(0, nd, 0);
- if TanLoc > -1 then
- gl.VertexAttrib3f(TanLoc, nd, 0, 0);
- if BinLoc > -1 then
- gl.VertexAttrib3f(BinLoc, 0, 0, -nd);
- xgl.TexCoord2fv(@YTexPoint);
- gl.Vertex3f(v1.X, v2.Y, v1.Z);
- xgl.TexCoord2fv(@NullTexPoint);
- gl.Vertex3f(v1d.X, v2.Y, v2d.Z);
- xgl.TexCoord2fv(@XTexPoint);
- gl.Vertex3fv(@v2);
- xgl.TexCoord2fv(@XYTexPoint);
- gl.Vertex3f(v2d.X, v2.Y, v1d.Z);
- end;
- if cpBottom in FParts then
- begin
- gl.Normal3f(0, -nd, 0);
- if TanLoc > -1 then
- gl.VertexAttrib3f(TanLoc, -nd, 0, 0);
- if BinLoc > -1 then
- gl.VertexAttrib3f(BinLoc, 0, 0, nd);
- xgl.TexCoord2fv(@NullTexPoint);
- gl.Vertex3fv(@v1);
- xgl.TexCoord2fv(@XTexPoint);
- gl.Vertex3f(v2d.X, v1.Y, v1d.Z);
- xgl.TexCoord2fv(@XYTexPoint);
- gl.Vertex3f(v2.X, v1.Y, v2.Z);
- xgl.TexCoord2fv(@YTexPoint);
- gl.Vertex3f(v1d.X, v1.Y, v2d.Z);
- end;
- gl.End_;
- end;
- function TGLCube.GenerateSilhouette(const silhouetteParameters
- : TGLSilhouetteParameters): TGLSilhouette;
- var
- hw, hh, hd: TGLFloat;
- Connectivity: TGLConnectivity;
- sil: TGLSilhouette;
- begin
- Connectivity := TGLConnectivity.Create(True);
- hw := FCubeSize.X * 0.5;
- hh := FCubeSize.Y * 0.5;
- hd := FCubeSize.Z * 0.5;
- if cpFront in FParts then
- begin
- Connectivity.AddQuad(AffineVectorMake(hw, hh, hd),
- AffineVectorMake(-hw, hh, hd), AffineVectorMake(-hw, -hh, hd),
- AffineVectorMake(hw, -hh, hd));
- end;
- if cpBack in FParts then
- begin
- Connectivity.AddQuad(AffineVectorMake(hw, hh, -hd),
- AffineVectorMake(hw, -hh, -hd), AffineVectorMake(-hw, -hh, -hd),
- AffineVectorMake(-hw, hh, -hd));
- end;
- if cpLeft in FParts then
- begin
- Connectivity.AddQuad(AffineVectorMake(-hw, hh, hd),
- AffineVectorMake(-hw, hh, -hd), AffineVectorMake(-hw, -hh, -hd),
- AffineVectorMake(-hw, -hh, hd));
- end;
- if cpRight in FParts then
- begin
- Connectivity.AddQuad(AffineVectorMake(hw, hh, hd),
- AffineVectorMake(hw, -hh, hd), AffineVectorMake(hw, -hh, -hd),
- AffineVectorMake(hw, hh, -hd));
- end;
- if cpTop in FParts then
- begin
- Connectivity.AddQuad(AffineVectorMake(-hw, hh, -hd),
- AffineVectorMake(-hw, hh, hd), AffineVectorMake(hw, hh, hd),
- AffineVectorMake(hw, hh, -hd));
- end;
- if cpBottom in FParts then
- begin
- Connectivity.AddQuad(AffineVectorMake(-hw, -hh, -hd),
- AffineVectorMake(hw, -hh, -hd), AffineVectorMake(hw, -hh, hd),
- AffineVectorMake(-hw, -hh, hd));
- end;
- sil := nil;
- Connectivity.CreateSilhouette(silhouetteParameters, sil, False);
- Result := sil;
- Connectivity.Free;
- end;
- function TGLCube.GetCubeWHD(const Index: Integer): TGLFloat;
- begin
- Result := FCubeSize.v[index];
- end;
- procedure TGLCube.SetCubeWHD(Index: Integer; aValue: TGLFloat);
- begin
- if aValue <> FCubeSize.v[index] then
- begin
- FCubeSize.v[index] := aValue;
- StructureChanged;
- end;
- end;
- procedure TGLCube.SetParts(aValue: TGLCubeParts);
- begin
- if aValue <> FParts then
- begin
- FParts := aValue;
- StructureChanged;
- end;
- end;
- procedure TGLCube.SetNormalDirection(aValue: TGLNormalDirection);
- begin
- if aValue <> FNormalDirection then
- begin
- FNormalDirection := aValue;
- StructureChanged;
- end;
- end;
- procedure TGLCube.Assign(Source: TPersistent);
- begin
- if Assigned(Source) and (Source is TGLCube) then
- begin
- FCubeSize := TGLCube(Source).FCubeSize;
- FParts := TGLCube(Source).FParts;
- FNormalDirection := TGLCube(Source).FNormalDirection;
- end;
- inherited Assign(Source);
- end;
- function TGLCube.AxisAlignedDimensionsUnscaled: TGLVector;
- begin
- Result.X := FCubeSize.X * 0.5;
- Result.Y := FCubeSize.Y * 0.5;
- Result.Z := FCubeSize.Z * 0.5;
- Result.W := 0;
- end;
- function TGLCube.RayCastIntersect(const rayStart, rayVector: TGLVector;
- intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil): Boolean;
- var
- p: array [0 .. 5] of TGLVector;
- rv: TGLVector;
- rs, r: TGLVector;
- i: Integer;
- t: Single;
- eSize: TAffineVector;
- begin
- rs := AbsoluteToLocal(rayStart);
- SetVector(rv, VectorNormalize(AbsoluteToLocal(rayVector)));
- eSize.X := FCubeSize.X * 0.5 + 0.0001;
- eSize.Y := FCubeSize.Y * 0.5 + 0.0001;
- eSize.Z := FCubeSize.Z * 0.5 + 0.0001;
- p[0] := XHmgVector;
- p[1] := YHmgVector;
- p[2] := ZHmgVector;
- SetVector(p[3], -1, 0, 0);
- SetVector(p[4], 0, -1, 0);
- SetVector(p[5], 0, 0, -1);
- for i := 0 to 5 do
- begin
- if VectorDotProduct(p[i], rv) > 0 then
- begin
- t := -(p[i].X * rs.X + p[i].Y * rs.Y + p[i].Z * rs.Z + 0.5 * FCubeSize.v
- [i mod 3]) / (p[i].X * rv.X + p[i].Y * rv.Y + p[i].Z * rv.Z);
- MakePoint(r, rs.X + t * rv.X, rs.Y + t * rv.Y, rs.Z + t * rv.Z);
- if (Abs(r.X) <= eSize.X) and (Abs(r.Y) <= eSize.Y) and
- (Abs(r.Z) <= eSize.Z) and
- (VectorDotProduct(VectorSubtract(r, rs), rv) > 0) then
- begin
- if Assigned(intersectPoint) then
- MakePoint(intersectPoint^, LocalToAbsolute(r));
- if Assigned(intersectNormal) then
- MakeVector(intersectNormal^, LocalToAbsolute(VectorNegate(p[i])));
- Result := True;
- Exit;
- end;
- end;
- end;
- Result := False;
- end;
- procedure TGLCube.DefineProperties(Filer: TFiler);
- begin
- inherited;
- Filer.DefineBinaryProperty('CubeSize', ReadData, WriteData,
- (FCubeSize.X <> 1) or (FCubeSize.Y <> 1) or (FCubeSize.Z <> 1));
- end;
- procedure TGLCube.ReadData(Stream: TStream);
- begin
- with Stream do
- begin
- Read(FCubeSize, SizeOf(TAffineVector));
- end;
- end;
- procedure TGLCube.WriteData(Stream: TStream);
- begin
- with Stream do
- begin
- Write(FCubeSize, SizeOf(TAffineVector));
- end;
- end;
- // ------------------
- // ------------------ TGLQuadricObject ------------------
- // ------------------
- constructor TGLQuadricObject.Create(AOwner: TComponent);
- begin
- inherited;
- FNormals := nsSmooth;
- FNormalDirection := ndOutside;
- end;
- procedure TGLQuadricObject.SetNormals(aValue: TGLNormalSmoothing);
- begin
- if aValue <> FNormals then
- begin
- FNormals := aValue;
- StructureChanged;
- end;
- end;
- procedure TGLQuadricObject.SetNormalDirection(aValue: TGLNormalDirection);
- begin
- if aValue <> FNormalDirection then
- begin
- FNormalDirection := aValue;
- StructureChanged;
- end;
- end;
- procedure TGLQuadricObject.SetupQuadricParams(quadric: PGLUquadricObj);
- const
- cNormalSmoothinToEnum: array [nsFlat .. nsNone] of Cardinal = (GLU_FLAT,
- GLU_SMOOTH, GLU_NONE);
- begin
- gluQuadricDrawStyle(quadric, GLU_FILL);
- gluQuadricNormals(quadric, cNormalSmoothinToEnum[FNormals]);
- SetNormalQuadricOrientation(quadric);
- gluQuadricTexture(quadric, True);
- end;
- procedure TGLQuadricObject.SetNormalQuadricOrientation(quadric: PGLUquadricObj);
- const
- cNormalDirectionToEnum: array [ndInside .. ndOutside] of Cardinal =
- (GLU_INSIDE, GLU_OUTSIDE);
- begin
- gluQuadricOrientation(quadric, cNormalDirectionToEnum[FNormalDirection]);
- end;
- procedure TGLQuadricObject.SetInvertedQuadricOrientation
- (quadric: PGLUquadricObj);
- const
- cNormalDirectionToEnum: array [ndInside .. ndOutside] of Cardinal =
- (GLU_OUTSIDE, GLU_INSIDE);
- begin
- gluQuadricOrientation(quadric, cNormalDirectionToEnum[FNormalDirection]);
- end;
- procedure TGLQuadricObject.Assign(Source: TPersistent);
- begin
- if Assigned(Source) and (Source is TGLQuadricObject) then
- begin
- FNormals := TGLQuadricObject(Source).FNormals;
- FNormalDirection := TGLQuadricObject(Source).FNormalDirection;
- end;
- inherited Assign(Source);
- end;
- // ------------------
- // ------------------ TGLSphere ------------------
- // ------------------
- constructor TGLSphere.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- FRadius := 0.5;
- FSlices := 16;
- FStacks := 16;
- FTop := 90;
- FBottom := -90;
- FStart := 0;
- FStop := 360;
- end;
- procedure TGLSphere.BuildList(var rci: TGLRenderContextInfo);
- var
- v1, v2, N1: TAffineVector;
- AngTop, AngBottom, AngStart, AngStop, StepV, StepH: Double;
- SinP, CosP, SinP2, CosP2, SinT, CosT, Phi, Phi2, Theta: Double;
- uTexCoord, uTexFactor, vTexFactor, vTexCoord0, vTexCoord1: Single;
- i, j: Integer;
- DoReverse: Boolean;
- begin
- DoReverse := (FNormalDirection = ndInside);
- rci.GLStates.PushAttrib([sttPolygon]);
- if DoReverse then
- rci.GLStates.InvertFrontFace;
- // common settings
- AngTop := DegToRad(1.0 * FTop);
- AngBottom := DegToRad(1.0 * FBottom);
- AngStart := DegToRad(1.0 * FStart);
- AngStop := DegToRad(1.0 * FStop);
- StepH := (AngStop - AngStart) / FSlices;
- StepV := (AngTop - AngBottom) / FStacks;
- gl.PushMatrix;
- gl.Scalef(Radius, Radius, Radius);
- // top cap
- if (FTop < 90) and (FTopCap in [ctCenter, ctFlat]) then
- begin
- gl.Begin_(GL_TRIANGLE_FAN);
- SinCosine(AngTop, SinP, CosP);
- xgl.TexCoord2f(0.5, 0.5);
- if DoReverse then
- gl.Normal3f(0, -1, 0)
- else
- gl.Normal3f(0, 1, 0);
- if FTopCap = ctCenter then
- gl.Vertex3f(0, 0, 0)
- else
- begin
- gl.Vertex3f(0, SinP, 0);
- N1 := YVector;
- if DoReverse then
- N1.Y := -N1.Y;
- end;
- v1.Y := SinP;
- Theta := AngStart;
- for i := 0 to FSlices do
- begin
- SinCosine(Theta, SinT, CosT);
- v1.X := CosP * SinT;
- v1.Z := CosP * CosT;
- if FTopCap = ctCenter then
- begin
- N1 := VectorPerpendicular(YVector, v1);
- if DoReverse then
- NegateVector(N1);
- end;
- xgl.TexCoord2f(SinT * 0.5 + 0.5, CosT * 0.5 + 0.5);
- gl.Normal3fv(@N1);
- gl.Vertex3fv(@v1);
- Theta := Theta + StepH;
- end;
- gl.End_;
- end;
- // main body
- Phi := AngTop;
- Phi2 := Phi - StepV;
- uTexFactor := 1 / FSlices;
- vTexFactor := 1 / FStacks;
- for j := 0 to FStacks - 1 do
- begin
- Theta := AngStart;
- SinCos(Phi, SinP, CosP);
- SinCos(Phi2, SinP2, CosP2);
- v1.Y := SinP;
- v2.Y := SinP2;
- vTexCoord0 := 1 - j * vTexFactor;
- vTexCoord1 := 1 - (j + 1) * vTexFactor;
- gl.Begin_(GL_TRIANGLE_STRIP);
- for i := 0 to FSlices do
- begin
- SinCos(Theta, SinT, CosT);
- v1.X := CosP * SinT;
- v2.X := CosP2 * SinT;
- v1.Z := CosP * CosT;
- v2.Z := CosP2 * CosT;
- uTexCoord := i * uTexFactor;
- xgl.TexCoord2f(uTexCoord, vTexCoord0);
- if DoReverse then
- begin
- N1 := VectorNegate(v1);
- gl.Normal3fv(@N1);
- end
- else
- gl.Normal3fv(@v1);
- gl.Vertex3fv(@v1);
- xgl.TexCoord2f(uTexCoord, vTexCoord1);
- if DoReverse then
- begin
- N1 := VectorNegate(v2);
- gl.Normal3fv(@N1);
- end
- else
- gl.Normal3fv(@v2);
- gl.Vertex3fv(@v2);
- Theta := Theta + StepH;
- end;
- gl.End_;
- Phi := Phi2;
- Phi2 := Phi2 - StepV;
- end;
- // bottom cap
- if (FBottom > -90) and (FBottomCap in [ctCenter, ctFlat]) then
- begin
- gl.Begin_(GL_TRIANGLE_FAN);
- SinCos(AngBottom, SinP, CosP);
- xgl.TexCoord2f(0.5, 0.5);
- if DoReverse then
- gl.Normal3f(0, 1, 0)
- else
- gl.Normal3f(0, -1, 0);
- if FBottomCap = ctCenter then
- gl.Vertex3f(0, 0, 0)
- else
- begin
- gl.Vertex3f(0, SinP, 0);
- if DoReverse then
- MakeVector(N1, 0, -1, 0)
- else
- begin
- N1 := YVector;
- NegateVector(N1);
- end;
- end;
- v1.Y := SinP;
- Theta := AngStop;
- for i := 0 to FSlices do
- begin
- SinCos(Theta, SinT, CosT);
- v1.X := CosP * SinT;
- v1.Z := CosP * CosT;
- if FBottomCap = ctCenter then
- begin
- N1 := VectorPerpendicular(AffineVectorMake(0, -1, 0), v1);
- if DoReverse then
- NegateVector(N1);
- end;
- xgl.TexCoord2f(SinT * 0.5 + 0.5, CosT * 0.5 + 0.5);
- gl.Normal3fv(@N1);
- gl.Vertex3fv(@v1);
- Theta := Theta - StepH;
- end;
- gl.End_;
- end;
- if DoReverse then
- rci.GLStates.InvertFrontFace;
- gl.PopMatrix;
- rci.GLStates.PopAttrib;
- end;
- function TGLSphere.RayCastIntersect(const rayStart, rayVector: TGLVector;
- intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil): Boolean;
- var
- i1, i2: TGLVector;
- localStart, localVector: TGLVector;
- begin
- // compute coefficients of quartic polynomial
- SetVector(localStart, AbsoluteToLocal(rayStart));
- SetVector(localVector, AbsoluteToLocal(rayVector));
- NormalizeVector(localVector);
- if RayCastSphereIntersect(localStart, localVector, NullHmgVector, Radius, i1,
- i2) > 0 then
- begin
- Result := True;
- if Assigned(intersectPoint) then
- SetVector(intersectPoint^, LocalToAbsolute(i1));
- if Assigned(intersectNormal) then
- begin
- i1.W := 0; // vector transform
- SetVector(intersectNormal^, LocalToAbsolute(i1));
- end;
- end
- else
- Result := False;
- end;
- function TGLSphere.GenerateSilhouette(const silhouetteParameters
- : TGLSilhouetteParameters): TGLSilhouette;
- var
- i, j: Integer;
- s, C, angleFactor: Single;
- sVec, tVec: TAffineVector;
- Segments: Integer;
- begin
- Segments := MaxInteger(FStacks, FSlices);
- // determine a local orthonormal matrix, viewer-oriented
- sVec := VectorCrossProduct(silhouetteParameters.SeenFrom, XVector);
- if VectorLength(sVec) < 1E-3 then
- sVec := VectorCrossProduct(silhouetteParameters.SeenFrom, YVector);
- tVec := VectorCrossProduct(silhouetteParameters.SeenFrom, sVec);
- NormalizeVector(sVec);
- NormalizeVector(tVec);
- // generate the silhouette (outline and capping)
- Result := TGLSilhouette.Create;
- angleFactor := (2 * PI) / Segments;
- for i := 0 to Segments - 1 do
- begin
- SinCosine(i * angleFactor, FRadius, s, C);
- Result.vertices.AddPoint(VectorCombine(sVec, tVec, s, C));
- j := (i + 1) mod Segments;
- Result.Indices.Add(i, j);
- if silhouetteParameters.CappingRequired then
- Result.CapIndices.Add(Segments, i, j)
- end;
- if silhouetteParameters.CappingRequired then
- Result.vertices.Add(NullHmgPoint);
- end;
- procedure TGLSphere.SetBottom(aValue: TGLAngleLimit180);
- begin
- if FBottom <> aValue then
- begin
- FBottom := aValue;
- StructureChanged;
- end;
- end;
- procedure TGLSphere.SetBottomCap(aValue: TGLCapType);
- begin
- if FBottomCap <> aValue then
- begin
- FBottomCap := aValue;
- StructureChanged;
- end;
- end;
- procedure TGLSphere.SetRadius(const aValue: TGLFloat);
- begin
- if aValue <> FRadius then
- begin
- FRadius := aValue;
- StructureChanged;
- end;
- end;
- procedure TGLSphere.SetSlices(aValue: TGLInt);
- begin
- if aValue <> FSlices then
- begin
- if aValue <= 0 then
- FSlices := 1
- else
- FSlices := aValue;
- StructureChanged;
- end;
- end;
- procedure TGLSphere.SetStacks(aValue: TGLInt);
- begin
- if aValue <> FStacks then
- begin
- if aValue <= 0 then
- FStacks := 1
- else
- FStacks := aValue;
- StructureChanged;
- end;
- end;
- procedure TGLSphere.SetStart(aValue: TGLAngleLimit360);
- begin
- if FStart <> aValue then
- begin
- Assert(aValue <= FStop);
- FStart := aValue;
- StructureChanged;
- end;
- end;
- procedure TGLSphere.SetStop(aValue: TGLAngleLimit360);
- begin
- if FStop <> aValue then
- begin
- Assert(aValue >= FStart);
- FStop := aValue;
- StructureChanged;
- end;
- end;
- procedure TGLSphere.SetTop(aValue: TGLAngleLimit180);
- begin
- if FTop <> aValue then
- begin
- FTop := aValue;
- StructureChanged;
- end;
- end;
- procedure TGLSphere.SetTopCap(aValue: TGLCapType);
- begin
- if FTopCap <> aValue then
- begin
- FTopCap := aValue;
- StructureChanged;
- end;
- end;
- procedure TGLSphere.Assign(Source: TPersistent);
- begin
- if Assigned(Source) and (Source is TGLSphere) then
- begin
- FRadius := TGLSphere(Source).FRadius;
- FSlices := TGLSphere(Source).FSlices;
- FStacks := TGLSphere(Source).FStacks;
- FBottom := TGLSphere(Source).FBottom;
- FTop := TGLSphere(Source).FTop;
- FStart := TGLSphere(Source).FStart;
- FStop := TGLSphere(Source).FStop;
- end;
- inherited Assign(Source);
- end;
- function TGLSphere.AxisAlignedDimensionsUnscaled: TGLVector;
- begin
- Result.X := Abs(FRadius);
- Result.Y := Result.X;
- Result.Z := Result.X;
- Result.W := 0;
- end;
- // ------------------
- // ------------------ TGLPolygonBase ------------------
- // ------------------
- constructor TGLPolygonBase.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- CreateNodes;
- FDivision := 10;
- FSplineMode := lsmLines;
- end;
- procedure TGLPolygonBase.CreateNodes;
- begin
- FNodes := TGLNodes.Create(Self);
- end;
- destructor TGLPolygonBase.Destroy;
- begin
- FNodes.Free;
- inherited Destroy;
- end;
- procedure TGLPolygonBase.Assign(Source: TPersistent);
- begin
- if Source is TGLPolygonBase then
- begin
- SetNodes(TGLPolygonBase(Source).FNodes);
- FDivision := TGLPolygonBase(Source).FDivision;
- FSplineMode := TGLPolygonBase(Source).FSplineMode;
- end;
- inherited Assign(Source);
- end;
- procedure TGLPolygonBase.NotifyChange(Sender: TObject);
- begin
- if Sender = Nodes then
- StructureChanged;
- inherited;
- end;
- procedure TGLPolygonBase.SetDivision(const Value: Integer);
- begin
- if Value <> FDivision then
- begin
- if Value < 1 then
- FDivision := 1
- else
- FDivision := Value;
- StructureChanged;
- end;
- end;
- procedure TGLPolygonBase.SetNodes(const aNodes: TGLNodes);
- begin
- FNodes.Assign(aNodes);
- StructureChanged;
- end;
- procedure TGLPolygonBase.SetSplineMode(const val: TGLLineSplineMode);
- begin
- if FSplineMode <> val then
- begin
- FSplineMode := val;
- StructureChanged;
- end;
- end;
- procedure TGLPolygonBase.AddNode(const coords: TGLCoordinates);
- var
- n: TGLNode;
- begin
- n := Nodes.Add;
- if Assigned(coords) then
- n.AsVector := coords.AsVector;
- StructureChanged;
- end;
- procedure TGLPolygonBase.AddNode(const X, Y, Z: TGLFloat);
- var
- n: TGLNode;
- begin
- n := Nodes.Add;
- n.AsVector := VectorMake(X, Y, Z, 1);
- StructureChanged;
- end;
- procedure TGLPolygonBase.AddNode(const Value: TGLVector);
- var
- n: TGLNode;
- begin
- n := Nodes.Add;
- n.AsVector := Value;
- StructureChanged;
- end;
- procedure TGLPolygonBase.AddNode(const Value: TAffineVector);
- var
- n: TGLNode;
- begin
- n := Nodes.Add;
- n.AsVector := VectorMake(Value);
- StructureChanged;
- end;
- // ------------------
- // ------------------ TGLSuperellipsoid ------------------
- // ------------------
- constructor TGLSuperellipsoid.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- FRadius := 0.5;
- FVCurve := 1.0;
- FHCurve := 1.0;
- FSlices := 16;
- FStacks := 16;
- FTop := 90;
- FBottom := -90;
- FStart := 0;
- FStop := 360;
- end;
- procedure TGLSuperellipsoid.BuildList(var rci: TGLRenderContextInfo);
- var
- CosPc1, SinPc1, CosTc2, SinTc2: Double;
- tc1, tc2: Integer;
- v1, v2, vs, N1: TAffineVector;
- AngTop, AngBottom, AngStart, AngStop, StepV, StepH: Double;
- SinP, CosP, SinP2, CosP2, SinT, CosT, Phi, Phi2, Theta: Double;
- uTexCoord, uTexFactor, vTexFactor, vTexCoord0, vTexCoord1: Double;
- i, j: Integer;
- DoReverse: Boolean;
- begin
- DoReverse := (FNormalDirection = ndInside);
- if DoReverse then
- rci.GLStates.InvertFrontFace;
- // common settings
- AngTop := DegToRad(1.0 * FTop);
- AngBottom := DegToRad(1.0 * FBottom);
- AngStart := DegToRad(1.0 * FStart);
- AngStop := DegToRad(1.0 * FStop);
- StepH := (AngStop - AngStart) / FSlices;
- StepV := (AngTop - AngBottom) / FStacks;
- { Even integer used with the Power function, only produce positive points }
- tc1 := trunc(VCurve);
- tc2 := trunc(HCurve);
- if tc1 mod 2 = 0 then
- VCurve := VCurve + 1E-6;
- if tc2 mod 2 = 0 then
- HCurve := HCurve - 1E-6;
- // top cap
- if (FTop < 90) and (FTopCap in [ctCenter, ctFlat]) then
- begin
- gl.Begin_(GL_TRIANGLE_FAN);
- SinCos(AngTop, SinP, CosP);
- xgl.TexCoord2f(0.5, 0.5);
- if DoReverse then
- gl.Normal3f(0, -1, 0)
- else
- gl.Normal3f(0, 1, 0);
- if FTopCap = ctCenter then
- gl.Vertex3f(0, 0, 0)
- else
- begin { FTopCap = ctFlat }
- if (Sign(SinP) = 1) or (tc1 = VCurve) then
- SinPc1 := Power(SinP, VCurve)
- else
- SinPc1 := -Power(-SinP, VCurve);
- gl.Vertex3f(0, SinPc1 * Radius, 0);
- N1 := YVector;
- if DoReverse then
- N1.Y := -N1.Y;
- end; { FTopCap = ctFlat }
- // v1.Y := SinP;
- if (Sign(SinP) = 1) or (tc1 = VCurve) then
- SinPc1 := Power(SinP, VCurve)
- else
- SinPc1 := -Power(-SinP, VCurve);
- v1.Y := SinPc1;
- Theta := AngStart;
- for i := 0 to FSlices do
- begin
- SinCos(Theta, SinT, CosT);
- // v1.X := CosP * SinT;
- if (Sign(CosP) = 1) or (tc1 = VCurve) then
- CosPc1 := Power(CosP, VCurve)
- else
- CosPc1 := -Power(-CosP, VCurve);
- if (Sign(SinT) = 1) or (tc2 = HCurve) then
- SinTc2 := Power(SinT, HCurve)
- else
- SinTc2 := -Power(-SinT, HCurve);
- v1.X := CosPc1 * SinTc2;
- // v1.Z := CosP * CosT;
- if (Sign(CosT) = 1) or (tc2 = HCurve) then
- CosTc2 := Power(CosT, HCurve)
- else
- CosTc2 := -Power(-CosT, HCurve);
- v1.Z := CosPc1 * CosTc2;
- if FTopCap = ctCenter then
- begin
- N1 := VectorPerpendicular(YVector, v1);
- if DoReverse then
- NegateVector(N1);
- end;
- // xgl.TexCoord2f(SinT * 0.5 + 0.5, CosT * 0.5 + 0.5);
- xgl.TexCoord2f(SinTc2 * 0.5 + 0.5, CosTc2 * 0.5 + 0.5);
- gl.Normal3fv(@N1);
- vs := v1;
- ScaleVector(vs, Radius);
- gl.Vertex3fv(@vs);
- Theta := Theta + StepH;
- end;
- gl.End_;
- end;
- // main body
- Phi := AngTop;
- Phi2 := Phi - StepV;
- uTexFactor := 1 / FSlices;
- vTexFactor := 1 / FStacks;
- for j := 0 to FStacks - 1 do
- begin
- Theta := AngStart;
- SinCos(Phi, SinP, CosP);
- SinCos(Phi2, SinP2, CosP2);
- if (Sign(SinP) = 1) or (tc1 = VCurve) then
- SinPc1 := Power(SinP, VCurve)
- else
- SinPc1 := -Power(-SinP, VCurve);
- v1.Y := SinPc1;
- if (Sign(SinP2) = 1) or (tc1 = VCurve) then
- SinPc1 := Power(SinP2, VCurve)
- else
- SinPc1 := -Power(-SinP2, VCurve);
- v2.Y := SinPc1;
- vTexCoord0 := 1 - j * vTexFactor;
- vTexCoord1 := 1 - (j + 1) * vTexFactor;
- gl.Begin_(GL_TRIANGLE_STRIP);
- for i := 0 to FSlices do
- begin
- SinCos(Theta, SinT, CosT);
- if (Sign(CosP) = 1) or (tc1 = VCurve) then
- CosPc1 := Power(CosP, VCurve)
- else
- CosPc1 := -Power(-CosP, VCurve);
- if (Sign(SinT) = 1) or (tc2 = HCurve) then
- SinTc2 := Power(SinT, HCurve)
- else
- SinTc2 := -Power(-SinT, HCurve);
- v1.X := CosPc1 * SinTc2;
- if (Sign(CosP2) = 1) or (tc1 = VCurve) then
- CosPc1 := Power(CosP2, VCurve)
- else
- CosPc1 := -Power(-CosP2, VCurve);
- v2.X := CosPc1 * SinTc2;
- if (Sign(CosP) = 1) or (tc1 = VCurve) then
- CosPc1 := Power(CosP, VCurve)
- else
- CosPc1 := -Power(-CosP, VCurve);
- if (Sign(CosT) = 1) or (tc2 = HCurve) then
- CosTc2 := Power(CosT, HCurve)
- else
- CosTc2 := -Power(-CosT, HCurve);
- v1.Z := CosPc1 * CosTc2;
- if (Sign(CosP2) = 1) or (tc1 = VCurve) then
- CosPc1 := Power(CosP2, VCurve)
- else
- CosPc1 := -Power(-CosP2, VCurve);
- v2.Z := CosPc1 * CosTc2;
- uTexCoord := i * uTexFactor;
- xgl.TexCoord2f(uTexCoord, vTexCoord0);
- if DoReverse then
- begin
- N1 := VectorNegate(v1);
- gl.Normal3fv(@N1);
- end
- else
- gl.Normal3fv(@v1);
- vs := v1;
- ScaleVector(vs, Radius);
- gl.Vertex3fv(@vs);
- xgl.TexCoord2f(uTexCoord, vTexCoord1);
- if DoReverse then
- begin
- N1 := VectorNegate(v2);
- gl.Normal3fv(@N1);
- end
- else
- gl.Normal3fv(@v2);
- vs := v2;
- ScaleVector(vs, Radius);
- gl.Vertex3fv(@vs);
- Theta := Theta + StepH;
- end;
- gl.End_;
- Phi := Phi2;
- Phi2 := Phi2 - StepV;
- end;
- // bottom cap
- if (FBottom > -90) and (FBottomCap in [ctCenter, ctFlat]) then
- begin
- gl.Begin_(GL_TRIANGLE_FAN);
- SinCos(AngBottom, SinP, CosP);
- xgl.TexCoord2f(0.5, 0.5);
- if DoReverse then
- gl.Normal3f(0, 1, 0)
- else
- gl.Normal3f(0, -1, 0);
- if FBottomCap = ctCenter then
- gl.Vertex3f(0, 0, 0)
- else
- begin { FTopCap = ctFlat }
- if (Sign(SinP) = 1) or (tc1 = VCurve) then
- SinPc1 := Power(SinP, VCurve)
- else
- SinPc1 := -Power(-SinP, VCurve);
- gl.Vertex3f(0, SinPc1 * Radius, 0);
- if DoReverse then
- MakeVector(N1, 0, -1, 0)
- else
- N1 := YVector;
- end;
- // v1.Y := SinP;
- if (Sign(SinP) = 1) or (tc1 = VCurve) then
- SinPc1 := Power(SinP, VCurve)
- else
- SinPc1 := -Power(-SinP, VCurve);
- v1.Y := SinPc1;
- Theta := AngStop;
- for i := 0 to FSlices do
- begin
- SinCos(Theta, SinT, CosT);
- // v1.X := CosP * SinT;
- if (Sign(CosP) = 1) or (tc1 = VCurve) then
- CosPc1 := Power(CosP, VCurve)
- else
- CosPc1 := -Power(-CosP, VCurve);
- if (Sign(SinT) = 1) or (tc2 = HCurve) then
- SinTc2 := Power(SinT, HCurve)
- else
- SinTc2 := -Power(-SinT, HCurve);
- v1.X := CosPc1 * SinTc2;
- // v1.Z := CosP * CosT;
- if (Sign(CosT) = 1) or (tc2 = HCurve) then
- CosTc2 := Power(CosT, HCurve)
- else
- CosTc2 := -Power(-CosT, HCurve);
- v1.Z := CosPc1 * CosTc2;
- if FBottomCap = ctCenter then
- begin
- N1 := VectorPerpendicular(AffineVectorMake(0, -1, 0), v1);
- if DoReverse then
- NegateVector(N1);
- gl.Normal3fv(@N1);
- end;
- // xgl.TexCoord2f(SinT * 0.5 + 0.5, CosT * 0.5 + 0.5);
- xgl.TexCoord2f(SinTc2 * 0.5 + 0.5, CosTc2 * 0.5 + 0.5);
- vs := v1;
- ScaleVector(vs, Radius);
- gl.Vertex3fv(@vs);
- Theta := Theta - StepH;
- end;
- gl.End_;
- end;
- if DoReverse then
- rci.GLStates.InvertFrontFace;
- end;
- // This will probably not work
- // RayCastSphereIntersect -> RayCastSuperellipsoidIntersect ?
- function TGLSuperellipsoid.RayCastIntersect(const rayStart, rayVector: TGLVector;
- intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil): Boolean;
- var
- i1, i2: TGLVector;
- localStart, localVector: TGLVector;
- begin
- // compute coefficients of quartic polynomial
- SetVector(localStart, AbsoluteToLocal(rayStart));
- SetVector(localVector, AbsoluteToLocal(rayVector));
- NormalizeVector(localVector);
- if RayCastSphereIntersect(localStart, localVector, NullHmgVector, Radius, i1,
- i2) > 0 then
- begin
- Result := True;
- if Assigned(intersectPoint) then
- SetVector(intersectPoint^, LocalToAbsolute(i1));
- if Assigned(intersectNormal) then
- begin
- i1.W := 0; // vector transform
- SetVector(intersectNormal^, LocalToAbsolute(i1));
- end;
- end
- else
- Result := False;
- end;
- // This will probably not work ?
- function TGLSuperellipsoid.GenerateSilhouette(const silhouetteParameters
- : TGLSilhouetteParameters): TGLSilhouette;
- var
- i, j: Integer;
- s, C, angleFactor: Single;
- sVec, tVec: TAffineVector;
- Segments: Integer;
- begin
- Segments := MaxInteger(FStacks, FSlices);
- // determine a local orthonormal matrix, viewer-oriented
- sVec := VectorCrossProduct(silhouetteParameters.SeenFrom, XVector);
- if VectorLength(sVec) < 1E-3 then
- sVec := VectorCrossProduct(silhouetteParameters.SeenFrom, YVector);
- tVec := VectorCrossProduct(silhouetteParameters.SeenFrom, sVec);
- NormalizeVector(sVec);
- NormalizeVector(tVec);
- // generate the silhouette (outline and capping)
- Result := TGLSilhouette.Create;
- angleFactor := (2 * PI) / Segments;
- for i := 0 to Segments - 1 do
- begin
- SinCosine(i * angleFactor, FRadius, s, C);
- Result.vertices.AddPoint(VectorCombine(sVec, tVec, s, C));
- j := (i + 1) mod Segments;
- Result.Indices.Add(i, j);
- if silhouetteParameters.CappingRequired then
- Result.CapIndices.Add(Segments, i, j)
- end;
- if silhouetteParameters.CappingRequired then
- Result.vertices.Add(NullHmgPoint);
- end;
- procedure TGLSuperellipsoid.SetBottom(aValue: TGLAngleLimit180);
- begin
- if FBottom <> aValue then
- begin
- FBottom := aValue;
- StructureChanged;
- end;
- end;
- procedure TGLSuperellipsoid.SetBottomCap(aValue: TGLCapType);
- begin
- if FBottomCap <> aValue then
- begin
- FBottomCap := aValue;
- StructureChanged;
- end;
- end;
- procedure TGLSuperellipsoid.SetHCurve(const aValue: TGLFloat);
- begin
- if aValue <> FHCurve then
- begin
- FHCurve := aValue;
- StructureChanged;
- end;
- end;
- procedure TGLSuperellipsoid.SetRadius(const aValue: TGLFloat);
- begin
- if aValue <> FRadius then
- begin
- FRadius := aValue;
- StructureChanged;
- end;
- end;
- procedure TGLSuperellipsoid.SetSlices(aValue: TGLInt);
- begin
- if aValue <> FSlices then
- begin
- if aValue <= 0 then
- FSlices := 1
- else
- FSlices := aValue;
- StructureChanged;
- end;
- end;
- procedure TGLSuperellipsoid.SetStacks(aValue: TGLInt);
- begin
- if aValue <> FStacks then
- begin
- if aValue <= 0 then
- FStacks := 1
- else
- FStacks := aValue;
- StructureChanged;
- end;
- end;
- procedure TGLSuperellipsoid.SetStart(aValue: TGLAngleLimit360);
- begin
- if FStart <> aValue then
- begin
- Assert(aValue <= FStop);
- FStart := aValue;
- StructureChanged;
- end;
- end;
- procedure TGLSuperellipsoid.SetStop(aValue: TGLAngleLimit360);
- begin
- if FStop <> aValue then
- begin
- Assert(aValue >= FStart);
- FStop := aValue;
- StructureChanged;
- end;
- end;
- procedure TGLSuperellipsoid.SetTop(aValue: TGLAngleLimit180);
- begin
- if FTop <> aValue then
- begin
- FTop := aValue;
- StructureChanged;
- end;
- end;
- procedure TGLSuperellipsoid.SetTopCap(aValue: TGLCapType);
- begin
- if FTopCap <> aValue then
- begin
- FTopCap := aValue;
- StructureChanged;
- end;
- end;
- procedure TGLSuperellipsoid.SetVCurve(const aValue: TGLFloat);
- begin
- if aValue <> FVCurve then
- begin
- FVCurve := aValue;
- StructureChanged;
- end;
- end;
- procedure TGLSuperellipsoid.Assign(Source: TPersistent);
- begin
- if Assigned(Source) and (Source is TGLSuperellipsoid) then
- begin
- FRadius := TGLSuperellipsoid(Source).FRadius;
- FSlices := TGLSuperellipsoid(Source).FSlices;
- FStacks := TGLSuperellipsoid(Source).FStacks;
- FBottom := TGLSuperellipsoid(Source).FBottom;
- FTop := TGLSuperellipsoid(Source).FTop;
- FStart := TGLSuperellipsoid(Source).FStart;
- FStop := TGLSuperellipsoid(Source).FStop;
- end;
- inherited Assign(Source);
- end;
- function TGLSuperellipsoid.AxisAlignedDimensionsUnscaled: TGLVector;
- begin
- Result.X := Abs(FRadius);
- Result.Y := Result.X;
- Result.Z := Result.X;
- Result.W := 0;
- end;
- // -------------------------------------------------------------
- initialization
- // -------------------------------------------------------------
- RegisterClasses([TGLSphere, TGLCube, TGLPlane, TGLSprite, TGLPoints,
- TGLDummyCube, TGLLines, TGLSuperellipsoid]);
- end.
|