1 /*
2 * NodeGeoLOD.cpp
3 *
4 * Copyright (C) 1999 Stephen F. White
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program (see the file "COPYING" for details); if
18 * not, write to the Free Software Foundation, Inc., 675 Mass Ave,
19 * Cambridge, MA 02139, USA.
20 */
21
22 #include <stdio.h>
23 #include "stdafx.h"
24
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #ifndef _WIN32
28 # include <unistd.h>
29 #endif
30
31 #include "NodeGeoLOD.h"
32 #include "NodeGeoOrigin.h"
33 #include "Proto.h"
34 #include "MFVec3f.h"
35 #include "ExposedField.h"
36 #include "Field.h"
37 #include "RenderState.h"
38 #include "DuneApp.h"
39 #include "resource.h"
40 #include "Util.h"
41 #include "Vec3f.h"
42 #include "Scene.h"
43 #include "NodeIndexedFaceSet.h"
44 #include "NodeIndexedLineSet.h"
45 #include "NodePointSet.h"
46
ProtoGeoLOD(Scene * scene)47 ProtoGeoLOD::ProtoGeoLOD(Scene *scene)
48 : GeoProto(scene, "GeoLOD")
49 {
50 bboxCenter.set(
51 addField(SFVEC3F, "bboxCenter", new SFVec3f(0.0f, 0.0f, 0.0f)));
52 setFieldFlags(bboxCenter, FF_X3D_ONLY);
53 bboxSize.set(
54 addField(SFVEC3F, "bboxSize", new SFVec3f(-1.0f, -1.0f, -1.0f),
55 new SFFloat(-1.0f)));
56 setFieldFlags(bboxSize, FF_X3D_ONLY);
57
58 center.set(
59 addField(SFSTRING, "center", new SFString("0.0 0.0 0.0")));
60 setFieldFlags(center, FF_VRML_ONLY);
61 centerX3D.set(
62 addField(SFVEC3D, "center", new SFVec3d(0.0, 0.0, 0.0)));
63 setFieldFlags(centerX3D, FF_X3D_ONLY);
64
65 child1Url.set(
66 addField(MFSTRING, "child1Url", new MFString()));
67 child2Url.set(
68 addField(MFSTRING, "child2Url", new MFString()));
69 child3Url.set(
70 addField(MFSTRING, "child3Url", new MFString()));
71 child4Url.set(
72 addField(MFSTRING, "child4Url", new MFString()));
73 range.set(
74 addField(MFFLOAT, "range", new MFFloat(), new SFFloat(0.0f)));
75 rootUrl.set(
76 addField(MFSTRING, "rootUrl", new MFString()));
77 rootNode.set(
78 addField(MFNODE, "rootNode", new MFNode(), CHILD_NODE));
79
80 referenceBindableDescription.set(
81 addExposedField(SFSTRING, "referenceBindableDescription",
82 new SFString("")));
83 setFieldFlags(referenceBindableDescription, FF_X3DOM_ONLY);
84
85 render.set(
86 addExposedField(SFBOOL, "render", new SFBool(true)));
87 setFieldFlags(render, FF_X3DOM_ONLY);
88
89 addEventOut(MFNODE, "children");
90 addEventOut(SFINT32, "level_changed", FF_X3D_ONLY);
91 }
92
93 Node *
create(Scene * scene)94 ProtoGeoLOD::create(Scene *scene)
95 {
96 return new NodeGeoLOD(scene, this);
97 }
98
99 int
translateField(int field) const100 ProtoGeoLOD::translateField(int field) const
101 {
102 bool x3d = m_scene->isX3d();
103 if (x3d && (field == center))
104 return centerX3D;
105 else if (!x3d && (field == centerX3D))
106 return center;
107 return field;
108 }
109
110
NodeGeoLOD(Scene * scene,Proto * def)111 NodeGeoLOD::NodeGeoLOD(Scene *scene, Proto *def)
112 : GeoNode(scene, def)
113 {
114 }
115
116 void
setField(int index,FieldValue * value,int cf)117 NodeGeoLOD::setField(int index, FieldValue *value, int cf)
118 {
119 if (index == center_Field()) {
120 SFVec3d *value3d = new SFVec3d((SFString *)value);
121 Node::setField(centerX3D_Field(), value3d, cf);
122 }
123 Node::setField(index, value, cf);
124 update();
125 }
126
127 Node *
convert2Vrml(void)128 NodeGeoLOD::convert2Vrml(void)
129 {
130 const double *values = centerX3D()->getValue();
131 char buf[4096];
132 mysnprintf(buf, 4095, "%g %g %g", values[0], values[1], values[2]);
133 SFString *string = new SFString(buf);
134 center(string);
135 return NULL;
136 }
137
138 void
draw(int pass)139 NodeGeoLOD::draw(int pass)
140 {
141 Node *node = NULL;
142 switch (m_nodeToDrawIndex) {
143 case 0:
144 node = m_child1;
145 break;
146 case 1:
147 node = m_child2;
148 break;
149 case 2:
150 node = m_child3;
151 break;
152 case 3:
153 node = m_child4;
154 break;
155 default:
156 node = m_root;
157 }
158
159 if (node != NULL) {
160 glPushName(-1); // field offset
161
162 node->bind();
163
164 glPushName(0);
165
166 glLoadName(m_nodeToDrawIndex);
167 node->draw(pass);
168
169 glPopName();
170
171 node->unbind();
172
173 glPopName();
174 }
175 }
176
177 void
preDraw()178 NodeGeoLOD::preDraw()
179 {
180 accountNodeToDrawIndex();
181
182 Node *node = NULL;
183 switch (m_nodeToDrawIndex) {
184 case 0:
185 node = m_child1;
186 break;
187 case 1:
188 node = m_child2;
189 break;
190 case 2:
191 node = m_child3;
192 break;
193 case 3:
194 node = m_child4;
195 break;
196 default:
197 node = m_root;
198 }
199
200 if (node != NULL)
201 node->preDraw();
202 }
203
204 void
accountNodeToDrawIndex()205 NodeGeoLOD::accountNodeToDrawIndex()
206 {
207 int tmpNodeToDrawIndex = -1;
208
209 tmpNodeToDrawIndex = 4 - 1;
210 Matrixd matrix;
211 const double *fcenter = centerX3D()->getValue();
212
213 glPushMatrix();
214 glTranslated(fcenter[0], fcenter[1], fcenter[2]);
215 glGetDoublev(GL_MODELVIEW_MATRIX, matrix);
216 glPopMatrix();
217
218 NodeGeoOrigin *origin = (NodeGeoOrigin *)geoOrigin()->getValue();
219
220 Vec3d vec;
221 if (origin)
222 vec = origin->getVec();
223
224 Vec3d v(matrix[12], matrix[13], matrix[14]);
225 MFFloat *mfrange = range();
226 if (tmpNodeToDrawIndex > mfrange->getSize())
227 tmpNodeToDrawIndex = mfrange->getSize();
228 // vrml97/part1/nodesRef.html#LOD
229 // | An empty range field ... a hint to the browser that it may
230 // | choose a level automatically to maintain a constant display rate.
231 // we choose the first level 8-(
232 if (mfrange->getSize() > 0)
233 for (int i = tmpNodeToDrawIndex; i >= 0; i--)
234 if (i < mfrange->getSize())
235 if ((v - vec).length() < mfrange->getValues()[i])
236 tmpNodeToDrawIndex = i;
237
238 m_nodeToDrawIndex = -1;
239 if (tmpNodeToDrawIndex >= 0)
240 m_nodeToDrawIndex = tmpNodeToDrawIndex;
241 }
242
243 void
loadChild(Node * node,MFString * urls)244 NodeGeoLOD::loadChild(Node *node, MFString *urls)
245 {
246 if (urls->getSize() == 0)
247 return;
248 MyString m_baseURL = "";
249 m_baseURL += TheApp->getImportURL();
250 for (int i = 0; i < urls->getSize(); i++) {
251 MyString path;
252 URL urlI(m_baseURL, urls->getValue(i));
253 if (urls->getValue(i).length() == 0) continue;
254 if (m_scene->Download(urlI, &path)) {
255 TheApp->setImportURL(urlI.GetPath());
256 struct stat fileStat;
257 MyString filename = "";
258 filename += path;
259 if (stat(filename, &fileStat) == 0) {
260 if (S_ISREG(fileStat.st_mode)) {
261 bool oldX3d = m_scene->isX3d();
262 FILE *file = fopen(filename, "rb");
263 if (file == NULL) {
264 TheApp->MessageBoxPerror(IDS_URL_FILE_FAILED, filename);
265 continue;
266 }
267 // double oldUnitLength = getUnitLength();
268 // pushUnitLength();
269 TheApp->setImportFile(filename);
270 m_scene->parse(file, m_child1, -1, SCAN_FOR_BOTH);
271 // node->setUnitLength(oldUnitLength / getUnitLength());
272 // popUnitLength();
273 fclose(file);
274 if (oldX3d && (!m_scene->isX3d()))
275 m_scene->setX3d();
276 else if ((!oldX3d) && m_scene->isX3d())
277 m_scene->setVrml();
278 break;
279 }
280 }
281 }
282 }
283 }
284
285 void
load()286 NodeGeoLOD::load()
287 {
288 m_root = NULL;
289 loadChild(m_root, rootUrl());
290 m_child1 = NULL;
291 loadChild(m_child1, child1Url());
292 m_child2 = NULL;
293 loadChild(m_child2, child2Url());
294 m_child3 = NULL;
295 loadChild(m_child3, child3Url());
296 m_child4 = NULL;
297 loadChild(m_child4, child4Url());
298 }
299