File: v3dsceneoctreevisualize.pas

package info (click to toggle)
view3dscene 4.2.0-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 13,824 kB
  • sloc: pascal: 3,961; sh: 330; xml: 261; makefile: 133
file content (279 lines) | stat: -rw-r--r-- 7,650 bytes parent folder | download
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
276
277
278
279
{
  Copyright 2002-2022 Michalis Kamburelis.

  This file is part of "view3dscene".

  "view3dscene" is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  "view3dscene" 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.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with "view3dscene"; if not, write to the Free Software
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA

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

{ Visualizing the octree. }
unit V3DSceneOctreeVisualize;

{$I v3dsceneconf.inc}

interface

uses CastleInternalOctree, CastleWindow, CastleScene;

type
  TOctreeDisplay = object
  private
    procedure AddDisplayStatus(var S: string);
  public
    { Constructor, initially display is none (Whole = @false and Depth = -1). }
    constructor Init(const AName: string);
  public
    Whole: boolean;

    { Depth to dispay. Meaningful only if Whole = false.
      -1 means "don't display octree". }
    Depth: Integer;

    Name: string;

    MenuWhole: TMenuItemChecked;

    procedure DoMenuIncDepth;
    procedure DoMenuDecDepth;
    procedure DoMenuToggleWhole;
  end;

var
  OctreeTrianglesDisplay: TOctreeDisplay;
  OctreeVisibleShapesDisplay: TOctreeDisplay;
  OctreeCollidableShapesDisplay: TOctreeDisplay;

procedure OctreeDisplay(Scene: TCastleScene);

function OctreeDisplayStatus: string;

implementation

uses SysUtils,
  {$ifdef FPC} CastleGL, {$else} GL, GLExt, {$endif}
  CastleColors, CastleGLUtils, CastleShapes, CastleGLBoxes, V3DSceneBoxes;

{ TOctreeDisplay ------------------------------------------------------------- }

constructor TOctreeDisplay.Init(const AName: string);
begin
  Whole := false;
  Depth := -1;
  Name := AName;
end;

procedure TOctreeDisplay.DoMenuIncDepth;
begin
  if Whole then
  begin
    Whole := false;
    MenuWhole.Checked := Whole;
    Depth := -1;
  end;

  Inc(Depth);
end;

procedure TOctreeDisplay.DoMenuDecDepth;
begin
  if Whole then
  begin
    Whole := false;
    MenuWhole.Checked := Whole;
    Depth := -1;
  end;

  Dec(Depth);
  if Depth < -1 then Depth := -1;
end;

procedure TOctreeDisplay.DoMenuToggleWhole;
begin
  Whole := not Whole;
  if not Whole then
    Depth := -1;
end;

procedure TOctreeDisplay.AddDisplayStatus(var S: string);
begin
  if Whole then
    S += Format(', Octree %s display: whole', [Name]) else
  if Depth <> -1 then
    S += Format(', Octree %s display: depth %d', [Name, Depth]);
end;

{ ---------------------------------------------------------------------------- }

procedure OctreeDisplay(Scene: TCastleScene);

(* TODO:
  This should be rewritten to construct a TCastleScene with TLineSet inside.
  Rendering using glDrawBox3DWire relies on OpenGL immediate mode,
  not possible under OpenGLES,
  cumbersome (needs PushMatrix hack in view3dscene.lpr)
  under modern OpenGL with EnabledFixedFunction = false.
*)

{$ifndef OpenGLES} //TODO-es

  procedure DisplayOctreeDepth(octreenode: TOctreeNode;
    OctreeDisplayDepth: integer);
  var
    b0, b1, b2: boolean;
  begin
    with octreenode do
      if Depth = OctreeDisplayDepth then
      begin
        if not (IsLeaf and (ItemsCount = 0)) then
          glDrawBox3DWire(Box);
      end else
      if not IsLeaf then
      begin
        for b0 := false to true do
          for b1 := false to true do
            for b2 := false to true do
              DisplayOctreeDepth(TreeSubNodes[b0, b1, b2], OctreeDisplayDepth);
      end;
  end;

  procedure DisplayOctreeTrianglesDepth(OctreeDisplayDepth: integer);
  var
    ShapeList: TShapeList;
    Shape: TShape;
  begin
    { Octree is not always ready, as it's recalculation during animations
      may hurt. Also, Draw may be called in various situations even when Scene
      is not really ready (e.g. when showing errors after scene loading).
      Also, octrees for particular shapes are not necessarily
      created, since some shapes may be not collidable.
      So we have to carefully check here whether appropriate things
      are initialized. }

    if Scene <> nil then
    begin
      ShapeList := Scene.Shapes.TraverseList(true);
      for Shape in ShapeList do
        if Shape.InternalOctreeTriangles <> nil then
        begin
          glPushMatrix;
            glMultMatrix(Shape.State.Transformation.Transform);
            DisplayOctreeDepth(Shape.InternalOctreeTriangles.TreeRoot,
              OctreeDisplayDepth);
          glPopMatrix;
        end;
    end;
  end;

  procedure DisplayOctreeWhole(OctreeNode: TOctreeNode);
  var
    b0, b1, b2: boolean;
  begin
    with OctreeNode do
    begin
      if not (IsLeaf and (ItemsCount = 0)) then
        glDrawBox3DWire(Box);

      if not IsLeaf then
      begin
        for b0 := false to true do
          for b1 := false to true do
            for b2 := false to true do
              DisplayOctreeWhole(TreeSubNodes[b0, b1, b2]);
      end;
    end;
  end;

  procedure DisplayOctreeTrianglesWhole;
  var
    ShapeList: TShapeList;
    Shape: TShape;
  begin
    { Octree is not always ready, as it's recalculation during animations
      may hurt. Also, Draw may be called in various situations even when Scene
      is not really ready (e.g. when showing errors after scene loading).
      Also, octrees for particular shapes are not necessarily
      created, since some shapes may be not collidable.
      So we have to carefully check here whether appropriate things
      are initialized. }

    if Scene <> nil then
    begin
      ShapeList := Scene.Shapes.TraverseList(true);
      for Shape in ShapeList do
        if Shape.InternalOctreeTriangles <> nil then
        begin
          glPushMatrix;
            glMultMatrix(Shape.State.Transformation.Transform);
            DisplayOctreeWhole(Shape.InternalOctreeTriangles.TreeRoot);
          glPopMatrix;
        end;
    end;
  end;

begin
  if OctreeTrianglesDisplay.Whole then
  begin
    glColorv(Yellow);
    DisplayOctreeTrianglesWhole;
  end else
  if OctreeTrianglesDisplay.Depth >= 0 then
  begin
    glColorv(Yellow);
    DisplayOctreeTrianglesDepth(OctreeTrianglesDisplay.Depth);
  end;

  if OctreeVisibleShapesDisplay.Whole then
  begin
    glColorv(Blue);
    DisplayOctreeWhole(Scene.InternalOctreeRendering.TreeRoot);
  end else
  if OctreeVisibleShapesDisplay.Depth >= 0 then
  begin
    glColorv(Blue);
    DisplayOctreeDepth(Scene.InternalOctreeRendering.TreeRoot,
      OctreeVisibleShapesDisplay.Depth);
  end;

  if OctreeCollidableShapesDisplay.Whole then
  begin
    glColorv(Red);
    DisplayOctreeWhole(Scene.InternalOctreeDynamicCollisions.TreeRoot);
  end else
  if OctreeCollidableShapesDisplay.Depth >= 0 then
  begin
    glColorv(Red);
    DisplayOctreeDepth(Scene.InternalOctreeDynamicCollisions.TreeRoot,
      OctreeCollidableShapesDisplay.Depth);
  end;
{$else}
begin
{$endif}
end;

function OctreeDisplayStatus: string;
begin
  Result := '';
  OctreeTrianglesDisplay       .AddDisplayStatus(Result);
  OctreeVisibleShapesDisplay   .AddDisplayStatus(Result);
  OctreeCollidableShapesDisplay.AddDisplayStatus(Result);
end;

initialization
  OctreeTrianglesDisplay       .Init('triangles');
  OctreeVisibleShapesDisplay   .Init('visible shapes');
  OctreeCollidableShapesDisplay.Init('collidable shapes');
end.