1 /*
2  Copyright (C) 2010-2014 Kristian Duske
3 
4  This file is part of TrenchBroom.
5 
6  TrenchBroom 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 3 of the License, or
9  (at your option) any later version.
10 
11  TrenchBroom 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 TrenchBroom. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "TexCoordSystem.h"
21 
22 #include "Assets/Texture.h"
23 #include "Model/BrushFace.h"
24 
25 namespace TrenchBroom {
26     namespace Model {
~TexCoordSystemSnapshot()27         TexCoordSystemSnapshot::~TexCoordSystemSnapshot() {}
28 
restore()29         void TexCoordSystemSnapshot::restore() {
30             doRestore();
31         }
32 
~TexCoordSystem()33         TexCoordSystem::~TexCoordSystem() {}
34 
clone() const35         TexCoordSystem* TexCoordSystem::clone() const {
36             return doClone();
37         }
38 
takeSnapshot()39         TexCoordSystemSnapshot* TexCoordSystem::takeSnapshot() {
40             return doTakeSnapshot();
41         }
42 
xAxis() const43         Vec3 TexCoordSystem::xAxis() const {
44             return getXAxis();
45         }
46 
yAxis() const47         Vec3 TexCoordSystem::yAxis() const {
48             return getYAxis();
49         }
50 
resetTextureAxes(const Vec3 & normal)51         void TexCoordSystem::resetTextureAxes(const Vec3& normal) {
52             doResetTextureAxes(normal);
53         }
54 
resetTextureAxesToParaxial(const Vec3 & normal,const float angle)55         void TexCoordSystem::resetTextureAxesToParaxial(const Vec3& normal, const float angle) {
56             doResetTextureAxesToParaxial(normal, angle);
57         }
58 
resetTextureAxesToParallel(const Vec3 & normal,const float angle)59         void TexCoordSystem::resetTextureAxesToParallel(const Vec3& normal, const float angle) {
60             doResetTextureAxesToParaxial(normal, angle);
61         }
62 
getTexCoords(const Vec3 & point,const BrushFaceAttributes & attribs) const63         Vec2f TexCoordSystem::getTexCoords(const Vec3& point, const BrushFaceAttributes& attribs) const {
64             return doGetTexCoords(point, attribs);
65         }
66 
setRotation(const Vec3 & normal,const float oldAngle,const float newAngle)67         void TexCoordSystem::setRotation(const Vec3& normal, const float oldAngle, const float newAngle) {
68             doSetRotation(normal, oldAngle, newAngle);
69         }
70 
transform(const Plane3 & oldBoundary,const Mat4x4 & transformation,BrushFaceAttributes & attribs,bool lockTexture,const Vec3 & invariant)71         void TexCoordSystem::transform(const Plane3& oldBoundary, const Mat4x4& transformation, BrushFaceAttributes& attribs, bool lockTexture, const Vec3& invariant) {
72             doTransform(oldBoundary, transformation, attribs, lockTexture, invariant);
73         }
74 
updateNormal(const Vec3 & oldNormal,const Vec3 & newNormal,const BrushFaceAttributes & attribs)75         void TexCoordSystem::updateNormal(const Vec3& oldNormal, const Vec3& newNormal, const BrushFaceAttributes& attribs) {
76             if (oldNormal != newNormal)
77                 doUpdateNormal(oldNormal, newNormal, attribs);
78         }
79 
moveTexture(const Vec3 & normal,const Vec3 & up,const Vec3 & right,const Vec2f & offset,BrushFaceAttributes & attribs) const80         void TexCoordSystem::moveTexture(const Vec3& normal, const Vec3& up, const Vec3& right, const Vec2f& offset, BrushFaceAttributes& attribs) const {
81 
82             /*
83             const Vec3 direction  = crossed(up, right);
84             const Mat4x4 toPlane  = Mat4x4::ZerZ * planeProjectionMatrix(0.0, direction);
85             const Vec3 upPlane    = (toPlane * up).normalized();
86             const Vec3 rightPlane = (toPlane * right).normalized();
87             const Vec3 xPlane     = (toPlane * xAxis()).normalized();
88             const Vec3 yPlane     = (toPlane * yAxis()).normalized();
89 
90             size_t hIndex, vIndex;
91             float hFactor, vFactor;
92             if (rightPlane.firstComponent() == xPlane.firstComponent()) {
93                 hIndex = 0;
94                 vIndex = 1;
95                 if (rightPlane.dot(xPlane) > 0.0f)
96                     hFactor = -1.0f;
97                 else
98                     hFactor = +1.0f;
99                 if (upPlane.dot(yPlane) > 0.0f)
100                     vFactor = -1.0f;
101                 else
102                     vFactor = +1.0f;
103             } else {
104                 hIndex = 1;
105                 vIndex = 0;
106                 if (rightPlane.dot(yPlane) > 0.0f)
107                     hFactor = +1.0f;
108                 else
109                     hFactor = -1.0f;
110                 if (upPlane.dot(xPlane) > 0.0f)
111                     vFactor = +1.0f;
112                 else
113                     vFactor = -1.0f;
114             }
115 
116             Vec2f actualOffset;
117             actualOffset[hIndex] = hFactor * offset.x();
118             actualOffset[vIndex] = vFactor * offset.y();
119              */
120 
121             const Mat4x4 toPlane = planeProjectionMatrix(0.0, normal);
122             const Mat4x4 fromPlane = invertedMatrix(toPlane);
123             const Mat4x4 transform = fromPlane * Mat4x4::ZerZ * toPlane;
124             const Vec3 texX = (transform * getXAxis()).normalized();
125             const Vec3 texY = (transform * getYAxis()).normalized();
126 
127             Vec3 vAxis, hAxis;
128             size_t xIndex = 0;
129             size_t yIndex = 0;
130 
131             // we prefer to use the texture axis which is closer to the XY plane for horizontal movement
132             if (Math::lt(std::abs(texX.z()), std::abs(texY.z()))) {
133                 hAxis = texX;
134                 vAxis = texY;
135                 xIndex = 0;
136                 yIndex = 1;
137             } else if (Math::lt(std::abs(texY.z()), std::abs(texX.z()))) {
138                 hAxis = texY;
139                 vAxis = texX;
140                 xIndex = 1;
141                 yIndex = 0;
142             } else {
143                 // both texture axes have the same absolute angle towards the XY plane, prefer the one that is closer
144                 // to the right view axis for horizontal movement
145 
146                 if (Math::gt(std::abs(right.dot(texX)), std::abs(right.dot(texY)))) {
147                     // the right view axis is closer to the X texture axis
148                     hAxis = texX;
149                     vAxis = texY;
150                     xIndex = 0;
151                     yIndex = 1;
152                 } else if (Math::gt(std::abs(right.dot(texY)), std::abs(right.dot(texX)))) {
153                     // the right view axis is closer to the Y texture axis
154                     hAxis = texY;
155                     vAxis = texX;
156                     xIndex = 1;
157                     yIndex = 0;
158                 } else {
159                     // the right axis is as close to the X texture axis as to the Y texture axis
160                     // test the up axis
161                     if (Math::gt(std::abs(up.dot(texY)), std::abs(up.dot(texX)))) {
162                         // the up view axis is closer to the Y texture axis
163                         hAxis = texX;
164                         vAxis = texY;
165                         xIndex = 0;
166                         yIndex = 1;
167                     } else if (Math::gt(std::abs(up.dot(texX)), std::abs(up.dot(texY)))) {
168                         // the up view axis is closer to the X texture axis
169                         hAxis = texY;
170                         vAxis = texX;
171                         xIndex = 1;
172                         yIndex = 0;
173                     } else {
174                         // this is just bad, better to do nothing
175                         return;
176                     }
177                 }
178             }
179 
180             Vec2f actualOffset;
181             if (right.dot(hAxis) >= 0.0)
182                 actualOffset[xIndex] = -offset.x();
183             else
184                 actualOffset[xIndex] = +offset.x();
185             if (up.dot(vAxis) >= 0.0)
186                 actualOffset[yIndex] = -offset.y();
187             else
188                 actualOffset[yIndex] = +offset.y();
189 
190 
191             attribs.setOffset(attribs.offset() + actualOffset);
192         }
193 
rotateTexture(const Vec3 & normal,const float angle,BrushFaceAttributes & attribs) const194         void TexCoordSystem::rotateTexture(const Vec3& normal, const float angle, BrushFaceAttributes& attribs) const {
195             const float actualAngle = isRotationInverted(normal) ? - angle : angle;
196             attribs.setRotation(attribs.rotation() + actualAngle);
197         }
198 
shearTexture(const Vec3 & normal,const Vec2f & factors)199         void TexCoordSystem::shearTexture(const Vec3& normal, const Vec2f& factors) {
200             doShearTexture(normal, factors);
201         }
202 
toMatrix(const Vec2f & o,const Vec2f & s) const203         Mat4x4 TexCoordSystem::toMatrix(const Vec2f& o, const Vec2f& s) const {
204             const Vec3 x = safeScaleAxis(getXAxis(), s.x());
205             const Vec3 y = safeScaleAxis(getYAxis(), s.y());
206             const Vec3 z = getZAxis();
207 
208             return Mat4x4(x[0], x[1], x[2], o[0],
209                           y[0], y[1], y[2], o[1],
210                           z[0], z[1], z[2],  0.0,
211                            0.0,  0.0,  0.0,  1.0);
212 /*
213             const Vec3 xAxis(getXAxis() * scale.x());
214             const Vec3 yAxis(getYAxis() * scale.y());
215             const Vec3 zAxis(getZAxis());
216             const Vec3 origin(xAxis * -offset.x() + yAxis * -offset.y());
217 
218             return coordinateSystemMatrix(xAxis, yAxis, zAxis, origin);
219  */
220         }
221 
fromMatrix(const Vec2f & offset,const Vec2f & scale) const222         Mat4x4 TexCoordSystem::fromMatrix(const Vec2f& offset, const Vec2f& scale) const {
223             return invertedMatrix(toMatrix(offset, scale));
224         }
225 
measureAngle(const float currentAngle,const Vec2f & center,const Vec2f & point) const226         float TexCoordSystem::measureAngle(const float currentAngle, const Vec2f& center, const Vec2f& point) const {
227             return doMeasureAngle(currentAngle, center, point);
228         }
229 
computeTexCoords(const Vec3 & point,const Vec2f & scale) const230         Vec2f TexCoordSystem::computeTexCoords(const Vec3& point, const Vec2f& scale) const {
231             return Vec2f(point.dot(safeScaleAxis(getXAxis(), scale.x())),
232                          point.dot(safeScaleAxis(getYAxis(), scale.y())));
233         }
234 
235     }
236 }
237