ArenaZ
749 строк · 19.1 Кб
1unit uSuperellipsoid;
2
3interface
4
5{$I GLScene.inc}
6
7uses
8System.SysUtils,
9System.Classes,
10System.Math,
11//GLS
12GLVectorGeometry,
13GLVectorTypes,
14GLScene,
15OpenGLAdapter,
16OpenGLTokens,
17GLVectorLists,
18GLCrossPlatform,
19GLContext,
20GLSilhouette,
21GLColor,
22GLRenderContextInfo,
23GLBaseClasses,
24GLNodes,
25GLCoordinates;
26
27type
28
29// TNormalSmoothing
30//
31{ : Determines how and if normals are smoothed.<p>
32- nsFlat : facetted look<br>
33- nsSmooth : smooth look<br>
34- nsNone : unlighted rendering, usefull for decla texturing }
35TNormalSmoothing = (nsFlat, nsSmooth, nsNone);
36
37// TGLQuadricObject
38//
39{ : Base class for quadric objects.<p>
40Introduces some basic Quadric interaction functions (the actual quadric
41math is part of the GLU library). }
42TGLQuadricObject = class(TGLSceneObject)
43private
44
45FNormals: TNormalSmoothing;
46FNormalDirection: TNormalDirection;
47
48protected
49{ Protected Declarations }
50procedure SetNormals(aValue: TNormalSmoothing);
51procedure SetNormalDirection(aValue: TNormalDirection);
52procedure SetupQuadricParams(quadric: PGLUquadricObj);
53procedure SetNormalQuadricOrientation(quadric: PGLUquadricObj);
54procedure SetInvertedQuadricOrientation(quadric: PGLUquadricObj);
55
56public
57
58constructor Create(AOwner: TComponent); override;
59procedure Assign(Source: TPersistent); override;
60
61published
62
63property Normals: TNormalSmoothing read FNormals write SetNormals
64default nsSmooth;
65property NormalDirection: TNormalDirection read FNormalDirection
66write SetNormalDirection default ndOutside;
67end;
68
69TAngleLimit1 = -90 .. 90;
70TAngleLimit2 = 0 .. 360;
71TCapType = (ctNone, ctCenter, ctFlat);
72
73// TGLSuperellipsoid
74//
75{ : A Superellipsoid object.<p>
76The Superellipsoid can have top and bottom caps,
77as well as being just a slice of Superellipsoid. }
78TGLSuperellipsoid = class(TGLQuadricObject)
79private
80
81FRadius, FxyCurve, FzCurve: TGLFloat;
82FSlices, FStacks: TGLInt;
83FTop: TAngleLimit1;
84FBottom: TAngleLimit1;
85FStart: TAngleLimit2;
86FStop: TAngleLimit2;
87FTopCap, FBottomCap: TCapType;
88procedure SetBottom(aValue: TAngleLimit1);
89procedure SetBottomCap(aValue: TCapType);
90procedure SetRadius(const aValue: TGLFloat);
91procedure SetxyCurve(const aValue: TGLFloat);
92procedure SetzCurve(const aValue: TGLFloat);
93procedure SetSlices(aValue: TGLInt);
94procedure SetStart(aValue: TAngleLimit2);
95procedure SetStop(aValue: TAngleLimit2);
96procedure SetStacks(aValue: TGLInt);
97procedure SetTop(aValue: TAngleLimit1);
98procedure SetTopCap(aValue: TCapType);
99
100public
101
102constructor Create(AOwner: TComponent); override;
103procedure Assign(Source: TPersistent); override;
104
105procedure BuildList(var rci: TGLRenderContextInfo); override;
106function AxisAlignedDimensionsUnscaled: TVector; override;
107function RayCastIntersect(const rayStart, rayVector: TVector;
108intersectPoint: PVector = nil; intersectNormal: PVector = nil)
109: Boolean; override;
110
111function GenerateSilhouette(const silhouetteParameters
112: TGLSilhouetteParameters): TGLSilhouette; override;
113published
114
115property Bottom: TAngleLimit1 read FBottom write SetBottom default -90;
116property BottomCap: TCapType read FBottomCap write SetBottomCap
117default ctNone;
118property Radius: TGLFloat read FRadius write SetRadius;
119property xyCurve: TGLFloat read FxyCurve write SetxyCurve;
120property zCurve: TGLFloat read FzCurve write SetzCurve;
121property Slices: TGLInt read FSlices write SetSlices default 16;
122property Stacks: TGLInt read FStacks write SetStacks default 16;
123property Start: TAngleLimit2 read FStart write SetStart default 0;
124property Stop: TAngleLimit2 read FStop write SetStop default 360;
125property Top: TAngleLimit1 read FTop write SetTop default 90;
126property TopCap: TCapType read FTopCap write SetTopCap default ctNone;
127end;
128
129implementation
130
131// -------------------------------------------------------------
132// -------------------------------------------------------------
133// -------------------------------------------------------------
134
135uses
136GLSpline,
137XOpenGL,
138GLState;
139
140const
141cDefaultPointSize: Single = 1.0;
142
143// ------------------
144// ------------------ TGLQuadricObject ------------------
145// ------------------
146
147// Create
148//
149
150constructor TGLQuadricObject.Create(AOwner: TComponent);
151begin
152inherited;
153FNormals := nsSmooth;
154FNormalDirection := ndOutside;
155end;
156
157// SetNormals
158//
159
160procedure TGLQuadricObject.SetNormals(aValue: TNormalSmoothing);
161begin
162if aValue <> FNormals then
163begin
164FNormals := aValue;
165StructureChanged;
166end;
167end;
168
169// SetNormalDirection
170//
171
172procedure TGLQuadricObject.SetNormalDirection(aValue: TNormalDirection);
173begin
174if aValue <> FNormalDirection then
175begin
176FNormalDirection := aValue;
177StructureChanged;
178end;
179end;
180
181// SetupQuadricParams
182//
183
184procedure TGLQuadricObject.SetupQuadricParams(quadric: PGLUquadricObj);
185const
186cNormalSmoothinToEnum: array [nsFlat .. nsNone] of TGLEnum = (GLU_FLAT,
187GLU_SMOOTH, GLU_NONE);
188begin
189gluQuadricDrawStyle(quadric, GLU_FILL);
190gluQuadricNormals(quadric, cNormalSmoothinToEnum[FNormals]);
191SetNormalQuadricOrientation(quadric);
192gluQuadricTexture(quadric, True);
193end;
194
195// SetNormalQuadricOrientation
196//
197
198procedure TGLQuadricObject.SetNormalQuadricOrientation(quadric: PGLUquadricObj);
199const
200cNormalDirectionToEnum: array [ndInside .. ndOutside] of TGLEnum =
201(GLU_INSIDE, GLU_OUTSIDE);
202begin
203gluQuadricOrientation(quadric, cNormalDirectionToEnum[FNormalDirection]);
204end;
205
206// SetInvertedQuadricOrientation
207//
208
209procedure TGLQuadricObject.SetInvertedQuadricOrientation
210(quadric: PGLUquadricObj);
211const
212cNormalDirectionToEnum: array [ndInside .. ndOutside] of TGLEnum =
213(GLU_OUTSIDE, GLU_INSIDE);
214begin
215gluQuadricOrientation(quadric, cNormalDirectionToEnum[FNormalDirection]);
216end;
217
218// Assign
219//
220
221procedure TGLQuadricObject.Assign(Source: TPersistent);
222begin
223if Assigned(Source) and (Source is TGLQuadricObject) then
224begin
225FNormals := TGLQuadricObject(Source).FNormals;
226FNormalDirection := TGLQuadricObject(Source).FNormalDirection;
227end;
228inherited Assign(Source);
229end;
230
231// ------------------
232// ------------------ TGLSuperellipsoid ------------------
233// ------------------
234
235// Create
236//
237
238constructor TGLSuperellipsoid.Create(AOwner: TComponent);
239begin
240inherited Create(AOwner);
241FRadius := 0.5;
242FxyCurve := 1.0;
243FzCurve := 1.0;
244FSlices := 16;
245FStacks := 16;
246FTop := 90;
247FBottom := -90;
248FStart := 0;
249FStop := 360;
250end;
251
252// BuildList
253//
254
255procedure TGLSuperellipsoid.BuildList(var rci: TGLRenderContextInfo);
256var
257CosPc1, SinPc1, CosTc2, SinTc2: TGLFloat;
258
259tc1, tc2: TGLInt;
260v1, V2, N1: TAffineVector;
261AngTop, AngBottom, AngStart, AngStop, StepV, StepH: Extended;
262SinP, CosP, SinP2, CosP2, SinT, CosT, Phi, Phi2, Theta: Extended;
263uTexCoord, uTexFactor, vTexFactor, vTexCoord0, vTexCoord1: Single;
264i, j: Integer;
265DoReverse: Boolean;
266
267begin
268DoReverse := (FNormalDirection = ndInside);
269rci.GLStates.PushAttrib([sttPolygon]);
270if DoReverse then
271rci.GLStates.InvertGLFrontFace;
272
273// common settings
274AngTop := DegToRadian(1.0 * FTop);
275AngBottom := DegToRadian(1.0 * FBottom);
276AngStart := DegToRadian(1.0 * FStart);
277AngStop := DegToRadian(1.0 * FStop);
278StepH := (AngStop - AngStart) / FSlices;
279StepV := (AngTop - AngBottom) / FStacks;
280GL.PushMatrix;
281GL.Scalef(Radius, Radius, Radius);
282
283{ Even integer used with the Power function, only produce positive points }
284tc1 := trunc(xyCurve);
285tc2 := trunc(zCurve);
286if tc1 mod 2 = 0 then xyCurve := xyCurve + 1e-6;
287if tc2 mod 2 = 0 then zCurve := zCurve - 1e-6;
288
289// top cap
290if (FTop < 90) and (FTopCap in [ctCenter, ctFlat]) then
291begin
292glBegin(GL_TRIANGLE_FAN);
293SinCos(AngTop, SinP, CosP);
294xgl.TexCoord2f(0.5, 0.5);
295if DoReverse then
296GL.Normal3f(0, -1, 0)
297else
298GL.Normal3f(0, 1, 0);
299
300if FTopCap = ctCenter then
301glVertex3f(0, 0, 0)
302else
303begin { FTopCap = ctFlat }
304// glVertex3f(0, SinP, 0);
305if (Sign(SinP) = 1) or (tc1 = xyCurve)
306then SinPc1 := PowerSingle( SinP, xyCurve)
307else SinPc1 := -PowerSingle(-SinP, xyCurve);
308glVertex3f(0, SinPc1, 0);
309
310N1 := YVector;
311if DoReverse then
312N1.Y := -N1.Y;
313end; { FTopCap = ctFlat }
314
315// v1[1] := SinP;
316if (Sign(SinP) = 1) or (tc1 = xyCurve)
317then SinPc1 := Power( SinP, xyCurve)
318else SinPc1 := -Power(-SinP, xyCurve);
319v1.Y := SinPc1;
320
321Theta := AngStart;
322
323for i := 0 to FSlices do
324begin
325SinCos(Theta, SinT, CosT);
326// v1[0] := CosP * SinT;
327if (Sign(CosP) = 1) or (tc1 = xyCurve)
328then CosPc1 := Power( CosP, xyCurve)
329else CosPc1 := -Power(-CosP, xyCurve);
330
331if (Sign(SinT) = 1) or (tc2 = zCurve)
332then SinTc2 := Power( SinT, zCurve)
333else SinTc2 := -Power(-SinT, zCurve);
334v1.X := CosPc1 * SinTc2;
335
336// v1[2] := CosP * CosT;
337if (Sign(CosT) = 1) or (tc2 = zCurve)
338then CosTc2 := Power( CosT, zCurve)
339else CosTc2 := -Power(-CosT, zCurve);
340v1.Z := CosPc1 * CosTc2;
341
342if FTopCap = ctCenter then
343begin
344N1 := VectorPerpendicular(YVector, v1);
345if DoReverse then
346NegateVector(N1);
347end;
348// xgl.TexCoord2f(SinT * 0.5 + 0.5, CosT * 0.5 + 0.5);
349xgl.TexCoord2f(SinTc2 * 0.5 + 0.5, CosTc2 * 0.5 + 0.5);
350GL.Normal3fv(@N1);
351glVertex3fv(@v1);
352Theta := Theta + StepH;
353end;
354GL.End_;
355end;
356
357// main body
358Phi := AngTop;
359Phi2 := Phi - StepV;
360uTexFactor := 1 / FSlices;
361vTexFactor := 1 / FStacks;
362
363for j := 0 to FStacks - 1 do
364begin
365Theta := AngStart;
366SinCos(Phi, SinP, CosP);
367SinCos(Phi2, SinP2, CosP2);
368
369if (Sign(SinP) = 1) or (tc1 = xyCurve)
370then SinPc1 := Power( SinP, xyCurve)
371else SinPc1 := -Power(-SinP, xyCurve);
372v1.Y := SinPc1;
373
374if (Sign(SinP2) = 1) or (tc1 = xyCurve)
375then SinPc1 := Power( SinP2, xyCurve)
376else SinPc1 := -Power(-SinP2, xyCurve);
377v2.Y := SinPc1;
378
379vTexCoord0 := 1 - j * vTexFactor;
380vTexCoord1 := 1 - (j + 1) * vTexFactor;
381
382glBegin(GL_TRIANGLE_STRIP);
383for i := 0 to FSlices do
384begin
385SinCos(Theta, SinT, CosT);
386
387if (Sign(CosP) = 1) or (tc1 = xyCurve)
388then CosPc1 := Power( CosP, xyCurve)
389else CosPc1 := -Power(-CosP, xyCurve);
390
391if (Sign(SinT) = 1) or (tc2 = zCurve)
392then SinTc2 := Power( SinT, zCurve)
393else SinTc2 := -Power(-SinT, zCurve);
394v1.X := CosPc1 * SinTc2;
395
396if (Sign(CosP2) = 1) or (tc1 = xyCurve)
397then CosPc1 := Power( CosP2, xyCurve)
398else CosPc1 := -Power(-CosP2, xyCurve);
399V2.X := CosPc1 * SinTc2;
400
401if (Sign(CosP) = 1) or (tc1 = xyCurve)
402then CosPc1 := Power( CosP, xyCurve)
403else CosPc1 := -Power(-CosP, xyCurve);
404
405if (Sign(CosT) = 1) or (tc2 = zCurve)
406then CosTc2 := Power( CosT, zCurve)
407else CosTc2 := -Power(-CosT, zCurve);
408v1.Z := CosPc1 * CosTc2;
409
410if (Sign(CosP2) = 1) or (tc1 = xyCurve)
411then CosPc1 := Power( CosP2, xyCurve)
412else CosPc1 := -Power(-CosP2, xyCurve);
413V2.Z := CosPc1 * CosTc2;
414
415uTexCoord := i * uTexFactor;
416xgl.TexCoord2f(uTexCoord, vTexCoord0);
417if DoReverse then
418begin
419N1 := VectorNegate(v1);
420GL.Normal3fv(@N1);
421end
422else
423GL.Normal3fv(@v1);
424glVertex3fv(@v1);
425
426xgl.TexCoord2f(uTexCoord, vTexCoord1);
427if DoReverse then
428begin
429N1 := VectorNegate(V2);
430GL.Normal3fv(@N1);
431end
432else
433GL.Normal3fv(@V2);
434glVertex3fv(@V2);
435
436Theta := Theta + StepH;
437end;
438GL.End_;
439Phi := Phi2;
440Phi2 := Phi2 - StepV;
441end;
442
443// bottom cap
444if (FBottom > -90) and (FBottomCap in [ctCenter, ctFlat]) then
445begin
446glBegin(GL_TRIANGLE_FAN);
447SinCos(AngBottom, SinP, CosP);
448xgl.TexCoord2f(0.5, 0.5);
449if DoReverse then
450GL.Normal3f(0, 1, 0)
451else
452GL.Normal3f(0, -1, 0);
453if FBottomCap = ctCenter then
454glVertex3f(0, 0, 0)
455else
456begin { FTopCap = ctFlat }
457// glVertex3f(0, SinP, 0);
458if (Sign(SinP) = 1) or (tc1 = xyCurve)
459then SinPc1 := Power( SinP, xyCurve)
460else SinPc1 := -Power(-SinP, xyCurve);
461glVertex3f(0, SinPc1, 0);
462
463if DoReverse then
464MakeVector(N1, 0, -1, 0)
465else
466N1 := YVector;
467end;
468// v1[1] := SinP;
469if (Sign(SinP) = 1) or (tc1 = xyCurve)
470then SinPc1 := Power( SinP, xyCurve)
471else SinPc1 := -Power(-SinP, xyCurve);
472v1.Y := SinPc1;
473
474Theta := AngStop;
475for i := 0 to FSlices do
476begin
477SinCos(Theta, SinT, CosT);
478// v1[0] := CosP * SinT;
479if (Sign(CosP) = 1) or (tc1 = xyCurve)
480then CosPc1 := Power( CosP, xyCurve)
481else CosPc1 := -Power(-CosP, xyCurve);
482
483if (Sign(SinT) = 1) or (tc2 = zCurve)
484then SinTc2 := Power( SinT, zCurve)
485else SinTc2 := -Power(-SinT, zCurve);
486v1.X := CosPc1 * SinTc2;
487
488// v1[2] := CosP * CosT;
489if (Sign(CosT) = 1) or (tc2 = zCurve)
490then CosTc2 := Power( CosT, zCurve)
491else CosTc2 := -Power(-CosT, zCurve);
492v1.Z := CosPc1 * CosTc2;
493
494if FBottomCap = ctCenter then
495begin
496N1 := VectorPerpendicular(AffineVectorMake(0, -1, 0), v1);
497if DoReverse then
498NegateVector(N1);
499end;
500// xgl.TexCoord2f(SinT * 0.5 + 0.5, CosT * 0.5 + 0.5);
501xgl.TexCoord2f(SinTc2 * 0.5 + 0.5, CosTc2 * 0.5 + 0.5);
502GL.Normal3fv(@N1);
503glVertex3fv(@v1);
504Theta := Theta - StepH;
505end;
506GL.End_;
507end;
508if DoReverse then
509rci.GLStates.InvertGLFrontFace;
510GL.PopMatrix;
511rci.GLStates.PopAttrib;
512end;
513
514// RayCastIntersect
515// This will probably not work;
516// RayCastSphereIntersect -> RayCastSuperellipsoidIntersect ??????
517
518function TGLSuperellipsoid.RayCastIntersect(const rayStart, rayVector: TVector;
519intersectPoint: PVector = nil; intersectNormal: PVector = nil): Boolean;
520var
521i1, i2: TVector;
522localStart, localVector: TVector;
523begin
524// compute coefficients of quartic polynomial
525SetVector(localStart, AbsoluteToLocal(rayStart));
526SetVector(localVector, AbsoluteToLocal(rayVector));
527NormalizeVector(localVector);
528if RayCastSphereIntersect(localStart, localVector, NullHmgVector, Radius, i1,
529i2) > 0 then
530begin
531Result := True;
532if Assigned(intersectPoint) then
533SetVector(intersectPoint^, LocalToAbsolute(i1));
534if Assigned(intersectNormal) then
535begin
536i1.W := 0; // vector transform
537SetVector(intersectNormal^, LocalToAbsolute(i1));
538end;
539end
540else
541Result := False;
542end;
543
544// GenerateSilhouette
545// This will probably not work;
546
547function TGLSuperellipsoid.GenerateSilhouette(const silhouetteParameters
548: TGLSilhouetteParameters): TGLSilhouette;
549var
550i, j: Integer;
551s, C, angleFactor: Single;
552sVec, tVec: TAffineVector;
553Segments: Integer;
554begin
555Segments := MaxInteger(FStacks, FSlices);
556
557// determine a local orthonormal matrix, viewer-oriented
558sVec := VectorCrossProduct(silhouetteParameters.SeenFrom, XVector);
559if VectorLength(sVec) < 1E-3 then
560sVec := VectorCrossProduct(silhouetteParameters.SeenFrom, YVector);
561tVec := VectorCrossProduct(silhouetteParameters.SeenFrom, sVec);
562NormalizeVector(sVec);
563NormalizeVector(tVec);
564// generate the silhouette (outline and capping)
565Result := TGLSilhouette.Create;
566angleFactor := (2 * PI) / Segments;
567for i := 0 to Segments - 1 do
568begin
569SinCosine(i * angleFactor, FRadius, s, C);
570Result.vertices.AddPoint(VectorCombine(sVec, tVec, s, C));
571j := (i + 1) mod Segments;
572Result.Indices.Add(i, j);
573if silhouetteParameters.CappingRequired then
574Result.CapIndices.Add(Segments, i, j)
575end;
576if silhouetteParameters.CappingRequired then
577Result.vertices.Add(NullHmgPoint);
578end;
579
580// SetBottom
581//
582
583procedure TGLSuperellipsoid.SetBottom(aValue: TAngleLimit1);
584begin
585if FBottom <> aValue then
586begin
587FBottom := aValue;
588StructureChanged;
589end;
590end;
591
592// SetBottomCap
593//
594
595procedure TGLSuperellipsoid.SetBottomCap(aValue: TCapType);
596begin
597if FBottomCap <> aValue then
598begin
599FBottomCap := aValue;
600StructureChanged;
601end;
602end;
603
604// SetRadius
605//
606
607procedure TGLSuperellipsoid.SetRadius(const aValue: TGLFloat);
608begin
609if aValue <> FRadius then
610begin
611FRadius := aValue;
612StructureChanged;
613end;
614end;
615
616// SetxyCurve
617//
618
619procedure TGLSuperellipsoid.SetxyCurve(const aValue: TGLFloat);
620begin
621if aValue <> FxyCurve then
622begin
623FxyCurve := aValue;
624StructureChanged;
625end;
626end;
627
628// SetzCurve
629//
630
631procedure TGLSuperellipsoid.SetzCurve(const aValue: TGLFloat);
632begin
633if aValue <> FzCurve then
634begin
635FzCurve := aValue;
636StructureChanged;
637end;
638end;
639
640// SetSlices
641//
642
643procedure TGLSuperellipsoid.SetSlices(aValue: Integer);
644begin
645if aValue <> FSlices then
646begin
647if aValue <= 0 then
648FSlices := 1
649else
650FSlices := aValue;
651StructureChanged;
652end;
653end;
654
655// SetStacks
656//
657
658procedure TGLSuperellipsoid.SetStacks(aValue: TGLInt);
659begin
660if aValue <> FStacks then
661begin
662if aValue <= 0 then
663FStacks := 1
664else
665FStacks := aValue;
666StructureChanged;
667end;
668end;
669
670// SetStart
671//
672
673procedure TGLSuperellipsoid.SetStart(aValue: TAngleLimit2);
674begin
675if FStart <> aValue then
676begin
677Assert(aValue <= FStop);
678FStart := aValue;
679StructureChanged;
680end;
681end;
682
683// SetStop
684//
685
686procedure TGLSuperellipsoid.SetStop(aValue: TAngleLimit2);
687begin
688if FStop <> aValue then
689begin
690Assert(aValue >= FStart);
691FStop := aValue;
692StructureChanged;
693end;
694end;
695
696// SetTop
697//
698
699procedure TGLSuperellipsoid.SetTop(aValue: TAngleLimit1);
700begin
701if FTop <> aValue then
702begin
703FTop := aValue;
704StructureChanged;
705end;
706end;
707
708// SetTopCap
709//
710
711procedure TGLSuperellipsoid.SetTopCap(aValue: TCapType);
712begin
713if FTopCap <> aValue then
714begin
715FTopCap := aValue;
716StructureChanged;
717end;
718end;
719
720// Assign
721//
722
723procedure TGLSuperellipsoid.Assign(Source: TPersistent);
724begin
725if Assigned(Source) and (Source is TGLSuperellipsoid) then
726begin
727FRadius := TGLSuperellipsoid(Source).FRadius;
728FSlices := TGLSuperellipsoid(Source).FSlices;
729FStacks := TGLSuperellipsoid(Source).FStacks;
730FBottom := TGLSuperellipsoid(Source).FBottom;
731FTop := TGLSuperellipsoid(Source).FTop;
732FStart := TGLSuperellipsoid(Source).FStart;
733FStop := TGLSuperellipsoid(Source).FStop;
734end;
735inherited Assign(Source);
736end;
737
738// AxisAlignedDimensions
739//
740
741function TGLSuperellipsoid.AxisAlignedDimensionsUnscaled: TVector;
742begin
743Result.X := Abs(FRadius);
744Result.Y := Result.X;
745Result.Z := Result.X;
746Result.W := 0;
747end;
748
749end.
750