/usr/src/castle-game-engine-5.2.0/x3d/x3dnodes_sphere.inc is in castle-game-engine-src 5.2.0-2.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 | {
Copyright 2002-2014 Michalis Kamburelis.
This file is part of "Castle Game Engine".
"Castle Game Engine" is free software; see the file COPYING.txt,
included in this distribution, for details about the copyright.
"Castle Game Engine" is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
----------------------------------------------------------------------------
}
{ Make a sphere. }
procedure Sphere_Proxy(CoordIndex: TLongIntList;
Coord: TVector3SingleList; Normal: TVector3SingleList;
TexCoord: TVector2SingleList;
OverTriangulate: boolean; const Radius: Single;
KambiTriangulation: TKambiTriangulationNode);
var
QuadricSlices, QuadricStacks: Cardinal;
{ We have rings numbered 0 ... QuadricStacks.
The rings nr 0 and QuadricStacks have 0 radius (bottom and top of the sphere). }
{ For stack number calculate it's radius and height (in y). }
procedure StackCircle(StackNum: integer; out StackRadius, Height: Single);
var
Alpha, S, C: Float;
begin
{ Calculate correct StackRadius and Height for sphere of radius 1,
and then scale by Radius. }
{ Divide the vertical ring into QuadricStacks equal pieces.
This is much better idea than simply dividing along the Height,
because it allows the top/bottom of the sphere to look much better.
This is also what OpenGL quadrics do.
You can compare by using below
StackRadius := Sqrt( 1 - Sqr(1 - 2*StackNum/QuadricStacks) ) * Radius;
Height := (-1 + StackNum * 2/QuadricStacks) * Radius;
}
Alpha := Pi * StackNum / QuadricStacks;
SinCos(Alpha, S, C);
StackRadius := S * Radius;
Height := -C * Radius;
end;
var
StackRadius, StackHeight: Single;
StackFaceIndex, BottomIndex, TopIndex, BottomCircleIndex, CircleIndex,
StackNum, I: Integer;
begin
{ For VRML 1.0, some of these MF fields by default have non-empty content.
It's safest to just clean them. }
CoordIndex.Count := 0;
Coord.Count := 0;
Normal.Count := 0;
if TexCoord <> nil then TexCoord.Count := 0;
QuadricSlices := KambiTriangulation.CalculateQuadricSlices;
QuadricStacks := KambiTriangulation.CalculateQuadricStacks;
{ We generate QuadricSlices + 1 points, not just QuadricSlices for each stack.
Reason: texture coordinates must be different at the last point
(1.0) than the first (0.0).
Otherwise texture seam would not be correctly closed. }
{ Even for the bottom/top point, we create many points, because
they need different tex coords. }
BottomIndex := Coord.Count;
Coord.Count := Coord.Count + QuadricSlices + 1;
Normal.Count := Normal.Count + QuadricSlices + 1;
for I := 0 to QuadricSlices do
begin
Coord.L[BottomIndex + I] := Vector3Single(0, -Radius, 0);
Normal.L[BottomIndex + I] := Vector3Single(0, -1, 0);
end;
if TexCoord <> nil then
begin
TexCoord.Count := TexCoord.Count + QuadricSlices + 1;
for I := 0 to QuadricSlices do
TexCoord.L[BottomIndex + I] := Vector2Single(I / QuadricSlices, 0);
end;
BottomCircleIndex := Coord.Count;
Coord.Count := Coord.Count + QuadricSlices + 1;
StackCircle(1, StackRadius, StackHeight);
GenerateCircle(QuadricSlices, StackRadius, StackHeight, Addr(Coord.L[BottomCircleIndex]));
Coord[Coord.Count - 1] := Coord.L[BottomCircleIndex];
Normal.Count := Normal.Count + QuadricSlices + 1;
for I := 0 to QuadricSlices - 1 do
Normal.L[BottomCircleIndex + I] := Normalized(Coord.L[BottomCircleIndex + I]);
Normal[Normal.Count - 1] := Normal.L[BottomCircleIndex];
if TexCoord <> nil then
begin
TexCoord.Count := TexCoord.Count + QuadricSlices + 1;
for I := 0 to QuadricSlices do
TexCoord.L[BottomCircleIndex + I] := Vector2Single(I / QuadricSlices, 1 / QuadricStacks);
end;
{ Bottom stack, from triangles }
StackFaceIndex := CoordIndex.Count;
CoordIndex.Count := CoordIndex.Count + QuadricSlices * 4;
for I := 0 to QuadricSlices - 1 do
begin
CoordIndex.L[StackFaceIndex + I * 4 ] := BottomCircleIndex + I + 1;
CoordIndex.L[StackFaceIndex + I * 4 + 1] := BottomCircleIndex + I;
CoordIndex.L[StackFaceIndex + I * 4 + 2] := BottomIndex + I;
CoordIndex.L[StackFaceIndex + I * 4 + 3] := -1;
end;
for StackNum := 2 to QuadricStacks - 1 do
begin
StackCircle(StackNum, StackRadius, StackHeight);
CircleIndex := Coord.Count;
Coord.Count := Coord.Count + QuadricSlices + 1;
StackCircle(StackNum, StackRadius, StackHeight);
GenerateCircle(QuadricSlices, StackRadius, StackHeight, Addr(Coord.L[CircleIndex]));
Coord[Coord.Count - 1] := Coord.L[CircleIndex];
Normal.Count := Normal.Count + QuadricSlices + 1;
for I := 0 to QuadricSlices - 1 do
Normal.L[CircleIndex + I] := Normalized(Coord.L[CircleIndex + I]);
Normal[Normal.Count - 1] := Normal.L[CircleIndex];
if TexCoord <> nil then
begin
TexCoord.Count := TexCoord.Count + QuadricSlices + 1;
for I := 0 to QuadricSlices do
TexCoord.L[CircleIndex + I] := Vector2Single(I / QuadricSlices, StackNum / QuadricStacks);
end;
{ Next stack, from quads }
StackFaceIndex := CoordIndex.Count;
CoordIndex.Count := CoordIndex.Count + QuadricSlices * 5;
for I := 0 to QuadricSlices - 1 do
begin
CoordIndex.L[StackFaceIndex + I * 5 ] := BottomCircleIndex + I;
CoordIndex.L[StackFaceIndex + I * 5 + 1] := BottomCircleIndex + I + 1;
CoordIndex.L[StackFaceIndex + I * 5 + 2] := CircleIndex + I + 1;
CoordIndex.L[StackFaceIndex + I * 5 + 3] := CircleIndex + I;
CoordIndex.L[StackFaceIndex + I * 5 + 4] := -1;
end;
BottomCircleIndex := CircleIndex;
end;
TopIndex := Coord.Count;
Coord.Count := Coord.Count + QuadricSlices + 1;
Normal.Count := Normal.Count + QuadricSlices + 1;
for I := 0 to QuadricSlices do
begin
Coord.L[TopIndex + I] := Vector3Single(0, Radius, 0);
Normal.L[TopIndex + I] := Vector3Single(0, 1, 0);
end;
if TexCoord <> nil then
begin
TexCoord.Count := TexCoord.Count + QuadricSlices + 1;
for I := 0 to QuadricSlices do
TexCoord.L[TopIndex + I] := Vector2Single(I / QuadricSlices, 1);
end;
{ Top stack, from triangles }
StackFaceIndex := CoordIndex.Count;
CoordIndex.Count := CoordIndex.Count + QuadricSlices * 4;
for I := 0 to QuadricSlices - 1 do
begin
CoordIndex.L[StackFaceIndex + I * 4 ] := BottomCircleIndex + I;
CoordIndex.L[StackFaceIndex + I * 4 + 1] := BottomCircleIndex + I + 1;
CoordIndex.L[StackFaceIndex + I * 4 + 2] := TopIndex + I;
CoordIndex.L[StackFaceIndex + I * 4 + 3] := -1;
end;
end;
function TSphereNode.Proxy(var State: TX3DGraphTraverseState;
const OverTriangulate: boolean): TAbstractGeometryNode;
var
CoordNode: TCoordinateNode;
NormalNode: TNormalNode;
TexCoordNode: TTextureCoordinateNode;
TexCoords: TVector2SingleList;
IFS: TIndexedFaceSetNode absolute Result;
begin
IFS := TIndexedFaceSetNode.Create(NodeName, BaseUrl);
try
CoordNode := TCoordinateNode.Create('', BaseUrl);
IFS.FdCoord.Value := CoordNode;
NormalNode := TNormalNode.Create('', BaseUrl);
IFS.FdNormal.Value := NormalNode;
IFS.FdNormalPerVertex.Value := true;
if (FdTexCoord.Value <> nil) and FdTexCoord.CurrentChildAllowed then
begin
{ No need for CylinderCone_Proxy to create tex coords. }
IFS.FdTexCoord.Value := FdTexCoord.Value;
TexCoords := nil;
end else
begin
TexCoordNode := TTextureCoordinateNode.Create('', BaseUrl);
IFS.FdTexCoord.Value := TexCoordNode;
TexCoords := TexCoordNode.FdPoint.Items;
end;
Sphere_Proxy(IFS.FdCoordIndex.Items,
CoordNode.FdPoint.Items, NormalNode.FdVector.Items, TexCoords,
OverTriangulate, FdRadius.Value,
State.LastNodes.KambiTriangulation);
IFS.FdSolid.Value := FdSolid.Value;
{ Smooth everything. }
IFS.FdCreaseAngle.Value := 4;
except FreeAndNil(Result); raise end;
end;
function TSphereNode_1.Proxy(var State: TX3DGraphTraverseState;
const OverTriangulate: boolean): TAbstractGeometryNode;
var
CoordNode: TCoordinate3Node_1;
NormalNode: TNormalNode;
NormalBinding: TNormalBindingNode_1;
TexCoordNode: TTextureCoordinate2Node_1;
ShapeHints: TShapeHintsNode_1;
MaterialBinding: TMaterialBindingNode_1;
IFS: TIndexedFaceSetNode_1 absolute Result;
begin
IFS := TIndexedFaceSetNode_1.Create(NodeName, BaseUrl);
try
{ we have to modify State, so make a copy of it }
State := TX3DGraphTraverseState.CreateCopy(State);
CoordNode := TCoordinate3Node_1.Create('', BaseUrl);
State.SetLastNodes(vsCoordinate3, CoordNode, true);
NormalNode := TNormalNode.Create('', BaseUrl);
State.SetLastNodes(vsNormal, NormalNode, true);
NormalBinding := TNormalBindingNode_1.Create('', BaseUrl);
{ NormalBinding.value = PER_VERTEX means we use niPerVertexCoordIndexed,
so coordIndex chooses the normal. }
NormalBinding.FdValue.Value := BIND_PER_VERTEX;
State.SetLastNodes(vsNormalBinding, NormalBinding, true);
TexCoordNode := TTextureCoordinate2Node_1.Create('', BaseUrl);
State.SetLastNodes(vsTextureCoordinate2, TexCoordNode, true);
ShapeHints := TShapeHintsNode_1.Create('', BaseUrl);
{ For VRML 1.0, Sphere is never solid. }
ShapeHints.FdshapeType.Value := SHTYPE_UNKNOWN;
ShapeHints.FdvertexOrdering.Value := VERTORDER_COUNTERCLOCKWISE;
{ Smooth everything. Not really needed, we use explicit normal node now. }
ShapeHints.FdCreaseAngle.Value := 4;
State.SetLastNodes(vsShapeHints, ShapeHints, true);
{ calculate MaterialBinding. Sphere has always only 1 material. }
MaterialBinding := TMaterialBindingNode_1.Create('', BaseUrl);
MaterialBinding.FdValue.Value := BIND_OVERALL;
State.SetLastNodes(vsMaterialBinding, MaterialBinding, true);
Sphere_Proxy(IFS.FdCoordIndex.Items,
CoordNode.FdPoint.Items, NormalNode.FdVector.Items,
TexCoordNode.FdPoint.Items,
OverTriangulate, FdRadius.Value,
State.LastNodes.KambiTriangulation);
{ For VRML 1.0, unfortunately textureCoordIndex must be set
(even though it's exactly equivalent to coordIndex).
This is a problem of VRML 1.0 "state" idea --- there is no
other way to "turn off" texture than to just use empty textureCoordIndex. }
IFS.FdTextureCoordIndex.Items.Assign(IFS.FdCoordIndex.Items);
except FreeAndNil(Result); raise end;
end;
|