1 /*
2  * NodeGeoTransform.cpp
3  *
4  * Copyright (C) 2009, 2019 J. "MUFTI" Scheurich
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 "NodeGeoTransform.h"
26 #include "Proto.h"
27 #include "FieldValue.h"
28 #include "MFNode.h"
29 #include "MFNode.h"
30 #include "MFNode.h"
31 #include "SFVec3d.h"
32 #include "SFRotation.h"
33 #include "SFVec3f.h"
34 #include "SFRotation.h"
35 #include "SFVec3f.h"
36 #include "SFVec3f.h"
37 #include "SFVec3f.h"
38 #include "SFNode.h"
39 #include "MFString.h"
40 #include "Scene.h"
41 #include "DuneApp.h"
42 
43 #include "NodeGeoOrigin.h"
44 
ProtoGeoTransform(Scene * scene)45 ProtoGeoTransform::ProtoGeoTransform(Scene *scene)
46   : GeoProto(scene, "GeoTransform")
47 {
48     children.set(
49         addExposedField(MFNODE, "children", new MFNode()));
50     geoCenter.set(
51         addExposedField(SFVEC3D, "geoCenter", new SFVec3d(0, 0, 0)));
52     rotation.set(
53         addExposedField(SFROTATION, "rotation", new SFRotation(0, 0, 1, 0)));
54     scale.set(
55         addExposedField(SFVEC3F, "scale", new SFVec3f(1, 1, 1)));
56     scaleOrientation.set(
57         addExposedField(SFROTATION, "scaleOrientation", new SFRotation(0, 0, 1, 0)));
58     translation.set(
59         addExposedField(SFVEC3F, "translation", new SFVec3f(0, 0, 0)));
60     bboxCenter.set(
61         addField(SFVEC3F, "bboxCenter", new SFVec3f(0, 0, 0)));
62     bboxSize.set(
63         addField(SFVEC3F, "bboxSize", new SFVec3f(-1, -1, -1)));
64 
65     globalGeoOrigin.set(
66           addExposedField(SFBOOL, "globalGeoOrigin", new SFBool(false)));
67     setFieldFlags(globalGeoOrigin, FF_X3DOM_ONLY);
68 
69     render.set(
70         addExposedField(SFBOOL, "render", new SFBool(true)));
71     setFieldFlags(render, FF_X3DOM_ONLY);
72 
73     addEventIn(MFNODE, "addChildren");
74     addEventIn(MFNODE, "removeChildren");
75 }
76 
77 Node *
create(Scene * scene)78 ProtoGeoTransform::create(Scene *scene)
79 {
80     return new NodeGeoTransform(scene, this);
81 }
82 
NodeGeoTransform(Scene * scene,Proto * def)83 NodeGeoTransform::NodeGeoTransform(Scene *scene, Proto *def)
84   : GeoNode(scene, def)
85 {
86     m_matrixDirty = true;
87 }
88 
89 void
transform()90 NodeGeoTransform::transform()
91 {
92     const double *fcenter = geoCenter()->getValue();
93     const float *frotation = rotation()->getValue();
94     const float *fscale = scale()->getValue();
95     const float *fscaleOrientation = scaleOrientation()->getValue();
96     const float *ftranslation = translation()->getValue();
97 
98     if (m_matrixDirty) {
99         double rotAngle = frotation[3];
100         double oriAngle = fscaleOrientation[3];
101         if (m_scene) {
102             double angleUnit = m_scene->getUnitAngle();
103             if (angleUnit != 0) {
104                rotAngle *= angleUnit;
105                oriAngle *= angleUnit;
106             }
107         }
108         double identity[16] = { 1, 0, 0, 0,
109                                 0, 1, 0, 0,
110                                 0, 0, 1, 0,
111                                 0, 0, 0, 1 };
112         glPushMatrix();
113         glMatrixMode(GL_MODELVIEW);
114         glLoadMatrixd(identity);
115         glTranslatef(ftranslation[0], ftranslation[1], ftranslation[2]);
116         glTranslated(fcenter[0], fcenter[1], fcenter[2]);
117         glRotatef(RAD2DEG(rotAngle),
118               frotation[0], frotation[1], frotation[2]);
119         glRotatef(RAD2DEG(oriAngle),
120               fscaleOrientation[0], fscaleOrientation[1], fscaleOrientation[2]);
121         glScalef(fscale[0], fscale[1], fscale[2]);
122         glRotatef(-RAD2DEG(oriAngle),
123               fscaleOrientation[0], fscaleOrientation[1], fscaleOrientation[2]);
124         glTranslated(-fcenter[0], -fcenter[1], -fcenter[2]);
125 
126         glGetDoublev(GL_MODELVIEW_MATRIX, m_matrix);
127 
128         m_matrixDirty = false;
129         glPopMatrix();
130     }
131 //for (int i = 0; i < 16; i++)
132 //printf("%lf ", m_matrix[i]);
133 //printf("\n");
134     glMultMatrixd(m_matrix);
135 }
136 
137 void
preDraw()138 NodeGeoTransform::preDraw()
139 {
140     NodeList *childList = children()->getValues();
141 
142     glPushMatrix();
143     transform();
144 
145     for (long i = 0; i < childList->size(); i++)
146         if (childList->get(i) != this)
147             childList->get(i)->preDraw();
148 
149     glPopMatrix();
150 }
151 
152 void
draw(int pass)153 NodeGeoTransform::draw(int pass)
154 {
155     int i;
156     NodeList *childList = children()->getValues();
157     int n = childList->size();
158 
159     glPushMatrix();
160 
161     NodeGeoOrigin *origin = (NodeGeoOrigin *)geoOrigin()->getValue();
162 
163     transform();
164 
165     if (origin) {
166         Vec3d vec = origin->getVec();
167         glTranslated(vec.x, vec.y, vec.z);
168     }
169 
170     for (i = 0; i < n; i++)
171         childList->get(i)->bind();
172 
173     glPushName(children_Field());  // field
174     glPushName(0);                 // index
175     for (i = 0; i < n; i++) {
176         glLoadName(i);
177         if (childList->get(i) != this)
178             childList->get(i)->draw(pass);
179     }
180     glPopName();
181     glPopName();
182 
183     for (i = 0; i < n; i++)
184         childList->get(i)->unbind();
185 
186     glPopMatrix();
187 }
188 
189 
190