File: build_3d_tunnel.lpr

package info (click to toggle)
castle-game-engine 6.4%2Bdfsg1-2
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 194,520 kB
  • sloc: pascal: 364,585; ansic: 8,606; java: 2,851; objc: 2,601; cpp: 1,412; xml: 851; makefile: 725; sh: 563; php: 26
file content (241 lines) | stat: -rw-r--r-- 7,443 bytes parent folder | download | duplicates (2)
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
{
  Copyright 2016-2017 Eugene Loza, 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.

  ----------------------------------------------------------------------------
}

{ Build a 3D tunnel using X3D mesh (IndexedFaceSet node). }
program build_3d_tunnel;

uses SysUtils, CastleWindow, CastleSceneCore, CastleScene, CastleVectors,
  X3dnodes, CastlePlayer, CastleKeysMouse, CastleRandom;

const
  { Amount of vertexes generated on the floor.
    Without randomization it doesn't matter. }
  FloorPoints = 12;
  { Amount of vertexes generated on the walls.
    It *must* be even because it's symmetric and each vertex must have a pair. }
  MaxPoints = FloorPoints + 20;

const
  { Length of the passage. }
  MaxSections = 10000;

type
  { Temporarily stores data about each section before they're added to global
    TCoordinateNode and TIndexedFaceSetNode nodes. }
  TSection = record
    { Average point and next average point for the section. }
    median, next: TVector3;
    { Vertexes constituting a section. }
    pt: array [1..MaxPoints] of TVector3;
    { Absolute (global) indexes of each vertex. }
    index: array [1..MaxPoints] of integer;
    { Angle the section faces. }
    angle: single;
    { Section's width and height. }
    width, height: single;
  end;

var
  { global variables of the Engine }
  Window: TCastleWindow;
  Scene: TCastleScene;
  player: TPlayer;

  { 3D geometry containers for the passage }
  ROOT: TX3DRootNode;             // contains all the geometry
  Shape: TShapeNode;              // contains the shape (coords and geometry)
  coords: TCoordinateNode;        // contains x,y,z of all vertexes
  Geometry: TIndexedFaceSetNode;  // face set of each wall&floor
  Appearance: TAppearanceNode;    // contains material
  Material: TMaterialNode;        // colored material

  { local variables used for generation }
  last_sect, next_sect: TSection;
  core_section: TSection;
  nindex: integer;   // global indexes of vertexes

{ Creates a shape of the section.
  Section is created with center point at 0,0,0.
  all points have z=0 and faces y axis direction. }
procedure create_core_section;
var
  i: integer;
begin
  with core_section do
  begin
    for i := 1 to FloorPoints do
    begin
      pt[i][0] := -1 + (i-1)/(FloorPoints-1)*2; // this is x-location of the floor vertexes
      pt[i][1] := 0;                            // y = 0
      pt[i][2] := 0;                            // z = 0
    end;
    for i := FloorPoints+1 to MaxPoints do
    begin
      pt[i][0] := 1 - (i-FloorPoints)/(MaxPoints-FloorPoints+1)*2;  //x and y of the vertexes
      pt[i][1] := 1 - sqr(sqr(abs(pt[i][0])));
      pt[i][2] := 0;                            // z = 0
    end;
  end;
end;

{ generates x,y,z coordinates for each section vertexes }
procedure create_section;
var
  i: integer;
begin
  with next_sect do
    for i := 1 to MaxPoints do
    begin
      pt[i][0] := median[0]+((core_section.pt[i][0])*cos(angle) + (core_section.pt[i][2])*sin(angle))*width;
      pt[i][2] := median[2]+((core_section.pt[i][2])*cos(angle) + (core_section.pt[i][0])*sin(angle))*width;
      pt[i][1] := median[1]+(core_section.pt[i][1])*height;
      inc(nindex);
      index[i] := nindex;
      Coords.FdPoint.Items.Add(Vector3(pt[i][0], pt[i][1], pt[i][2]));
    end;
end;

{ add vertexes indexes counter-clockwise to generate faces lookin inwards }
procedure pass;
var
  i, next_i: integer;
begin
  //amount of faces (quads) generated will be equal to amount of vertexes
  for i := 1 to MaxPoints do
  begin
    if i < MaxPoints then next_i := i+1 else next_i := 1; // handle last face correctly
    { add vertexes indexes counter-clockwise }
    Geometry.FdCoordIndex.Items.Add(last_sect.index[i]);
    Geometry.FdCoordIndex.Items.Add(last_sect.index[next_i]);
    Geometry.FdCoordIndex.Items.Add(next_sect.index[next_i]);
    Geometry.FdCoordIndex.Items.Add(next_sect.index[i]);
    { and finish the face by -1 }
    Geometry.FdCoordIndex.Items.Add(-1);
  end;
end;

{ this is the main procedure of the algorithm: makes a passage }
procedure MakePassage;
var
  j: integer;
begin
  for j := 1 to MaxSections do
  begin
    { determine next section parameters }
    next_sect.angle := last_sect.angle+(Rand.Random-0.5)/10;
    next_sect.median[0] := last_sect.median[0]+sin(next_sect.angle);
    next_sect.median[1] := last_sect.median[1]-(Rand.Random-0.5)/3;
    next_sect.median[2] := last_sect.median[2]-cos(next_sect.angle);
    next_sect.width := last_sect.width+(Rand.Random-0.5)/3;
    if next_sect.width < 1 then next_sect.width:=1;
    if next_sect.width > 3 then next_sect.width:=3;
    next_sect.height := last_sect.height+(Rand.Random-0.5)/3;
    if next_sect.height < 2 then next_sect.height:=2;
    if next_sect.height > 5 then next_sect.height:=5;
    { now create the section }
    create_section;
    { and connect it to previous section }
    pass;
    last_sect := next_sect;
  end;
end;


procedure generatemap;
begin
  { creates the passage shape }
  create_core_section;

  { initialize globai index counter }
  nindex := -1;

  { make first section to start with }
  //first set parameters
  last_sect.median[0] := 0;
  last_sect.median[1] := -2;
  last_sect.median[2] := 2;
  last_sect.width := 1+Rand.Random*2;
  last_sect.height := 2+Rand.Random*2;
  last_sect.angle := 0;
  //and generate the section
  create_section;

  { finally make the passage by generating the sequential sections }
  makePassage;
end;

begin
  { initialize TCoordinateNode and TIndexedFaceSetNode}
  Coords := TCoordinateNode.Create;
  Geometry := TIndexedFaceSetNode.Create;

  { generate the passage }
  generatemap;

  { merge Coords and Geometry }
  Geometry.Coord := Coords;

  { create some simple material }
  Material := TMaterialNode.Create;
  Material.DiffuseColor := Vector3(1, 0.9, 0.9);
  material.AmbientIntensity := 2;

  { and add it to Appearance node }
  Appearance := TAppearanceNode.Create;
  Appearance.Material := Material;

  { pack everything inside the Shape (geometry + appearance) }
  Shape := TShapeNode.Create;
  Shape.Geometry := Geometry;
  Shape.Appearance := Appearance;

  { and finally add everything to the Root node }
  Root := TX3DRootNode.Create;
  Root.AddChildren(shape);

  { Initialize Castle Window }

  Window := TCastleWindow.Create(Application);

  { Create player }

  Player := TPlayer.Create(Window.SceneManager);
  Window.SceneManager.Items.Add(Player);
  Window.SceneManager.Player := Player;

  { Create a scene based on Root node }

  Scene := TCastleScene.Create(Application);
  scene.load(Root,true);
  Scene.Spatial := [ssRendering, ssDynamicCollisions];
  Scene.ProcessEvents := true;

  { Add the scene to Scene Manager }

  Window.SceneManager.Items.Add(Scene);
  Window.SceneManager.MainScene := Scene;

  { Set some parameters for the player }

  Player.Translation := Vector3(0,0,-1);
  Player.Camera.MouseLook := true;
  Player.DefaultPreferredHeight := 1;
  Player.DefaultMoveHorizontalSpeed := 10;
  Window.SceneManager.Camera := Player.camera;

  { finally run the application }

  Window.OpenAndRun;
end.